初学者JavaScript模式

时间:2016-05-03 04:19:02

标签: javascript object design-patterns

我最近开始研究对象,闭包,范围等。我尝试使用这些技术实现自己的代码,但遇到了问题。

t

奇怪的是,这会返回function Person(name, age) { this.name = name; this.age = age; return { ageUp: function ageUp() { this.age++; }, printInfo: function printInfo() { console.log(this.name + " is " + this.age + " years old"); }, changeName: function changeName(newName) { this.name = newName; } } } var jeff = new Person('jeff', 28); jeff.printInfo(); undefined is undefined years old属性的范围是否没有printInfo,因为返回的对象没有函数的重新收集?

奇怪的是,如果我将this.namethis.name的所有实例更改为常规私有变量(例如this.age),则返回的对象将以某种方式正常运行并且我可以使用正如预期的那样var personName = name;ageUp

我是否将两种设计模式结合起来,我不应该这样做?什么是最好的方法呢?

4 个答案:

答案 0 :(得分:3)

问题是当你这样做时:

return { ...

您正在创建一个新对象,该对象与先前创建的new关键字的对象(您为其分配了两个属性的对象)分开。您可能会注意到jeff instanceof Person为false并且jeff.constructor === Object

见这个例子:

function Person(name, age) {
    this.name = name;
    this.age  = age;

    return {
        theObjectThatNewCreated: this
    }
}

var jeff = new Person('jeff', 28);
console.log( JSON.stringify( jeff ) );
// {"theObjectThatNewCreated":{"name":"jeff","age":28}}
console.log( jeff.constructor );
// Object
console.log( jeff.theObjectThatNewCreated.constructor );
// Person

您可以通过将名称和年龄属性分配给您返回的对象而不是this来修复它:

function Person(name, age) {
    return {
        name: name,
        age: age,
        ageUp: function ageUp() {
            this.age++;
        },
        printInfo: function printInfo() {
            console.log(this.name + " is " + this.age + " years old");
        },
        changeName: function changeName(newName) {
            this.name = newName;
        }
    }
}


var jeff = new Person('jeff', 28);
jeff.printInfo();

但是Person并不是一个真正的构造函数,它只是一个对象工厂,没有必要用new来调用它。它返回的对象不是Person的实例,它们是普通的旧对象。还有更好的方法。

  

我是否将两种设计模式结合起来,我不应该这样做?什么是最好的方法呢?

我想说你将揭示模块模式与普通的JavaScript构造函数结合起来。

不是返回一个新对象,而是可以一直使用this,将这些函数分配为Person对象的属性而不是新对象:

function Person(name, age) {
    this.name = name;
    this.age  = age;

    this.ageUp = function ageUp() {
        this.age++;
    };

    this.printInfo = function printInfo() {
        console.log(this.name + " is " + this.age + " years old");
    };

    this.changeName = function changeName(newName) {
        this.name = newName;
    };
}


var jeff = new Person('jeff', 28);
jeff.printInfo();

但是由于这些函数不使用构造函数中的任何闭合变量,所以它们实际上应该添加到构造函数的原型中:

function Person(name, age) {
    this.name = name;
    this.age  = age;
}

Person.prototype.ageUp = function ageUp() {
    this.age++;
};

Person.prototype.printInfo = function printInfo() {
    console.log(this.name + " is " + this.age + " years old");
};

Person.prototype.changeName = function changeName(newName) {
    this.name = newName;
};

var jeff = new Person('jeff', 28);
jeff.printInfo();

答案 1 :(得分:2)

你是正确的,因为你结合了两种模式。首先,在正常情况下,构造函数不会返回任何内容。 (有些例外情况我不会在这里深入探讨。)

你可能想做这样的事情:

function Person(name, age) {
    this.name = name;
    this.age  = age;
}

Person.prototype.printInfo = function() {
    console.log(this.name + " is " + this.age + " years old");
};

// and so on. Now you can say

var jeff = new Person('jeff', 28);
jeff.printInfo(); // => jeff is 28 years old

我假设您希望在原型上使用这些方法,以便共享它们(但这不是必须的)。

答案 2 :(得分:2)

您正在构造函数中返回一个新对象。因此,在调用Person而不是具有已定义属性的转储对象时,您将不会收到new Person(...)的实例。

尝试将您的方法对象定义为构造函数的原型:

function Person(name, age) {
    this.name = name;
    this.age  = age;
}

Person.prototype = {
    ageUp: function ageUp() {
        this.age++;
    },
    printInfo: function printInfo() {
        console.log(this.name + " is " + this.age + " years old");
    },
    changeName: function changeName(newName) {
        this.name = newName;
    }
}

或者,如果您想将属性nameage设为私有,则可以在构造函数中定义方法。只需将方法分配给this.即可。对于私有属性,您不必将属性本身分配给您的实例:

function Person(name, age) {
    this.ageUp = function ageUp() {
        age++;
    };

    this.printInfo = function printInfo() {
        console.log(name + " is " + age + " years old");
    };

    this.changeName = function changeName(newName) {
        name = newName;
    };
}

但我更喜欢第一个例子。在第二个中,每个新实例都将创建新方法。在第一个示例中,所有实例都引用一个原型对象,该对象应使用较少的内存。

答案 3 :(得分:0)

删除班级中的周围回复{},它应该有效。