初学者JavaScript模式

初学者JavaScript模式,javascript,object,design-patterns,Javascript,Object,Design Patterns,我最近开始研究对象、闭包、作用域等等。我试图用这些技术实现我自己的代码,但遇到了一些问题 function Person(name, age) { this.name = name; this.age = age; return { ageUp: function ageUp() { this.age++; }, printInfo: function printInfo() {

我最近开始研究对象、闭包、作用域等等。我试图用这些技术实现我自己的代码,但遇到了一些问题

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();
奇怪的是,这返回了
未定义的是未定义的年份
printInfo
属性的作用域中是否不包含
this.name
,因为返回的对象不记得函数

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


我是否结合了两种不应该的设计模式?最好的方法是什么?

在类中删除周围的返回{},它应该会工作。

问题是,当您这样做时:

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();

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

您可能希望执行以下操作:

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

我假设您希望在原型上共享这些方法(但这不是强制性的)。

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

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

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;
    }
}
或者,如果希望将属性
name
age
保持私有,则可以在构造函数中定义方法。只需将方法分配给此。。对于私有属性,不必将属性本身指定给实例:

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;
    };
}

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

回答得好,请您澄清一下“这些函数不使用构造函数中的任何闭合变量”这句话好吗?无法理解它…@chenop我指的是构造函数中用
var
声明的变量,或者构造函数的参数。