两者之间有什么区别

var A = function () {
    this.x = function () {
        //do something
    };
};

and

var A = function () { };
A.prototype.x = function () {
    //do something
};

当前回答

每个对象都链接到原型对象。当试图访问不存在的属性时,JavaScript将在对象的原型对象中查找该属性,如果该属性存在,则返回该属性。

函数构造函数的prototype属性引用使用new时使用该函数创建的所有实例的原型对象。


在第一个示例中,您将向使用a函数创建的每个实例添加属性x。

var A = function () {
    this.x = function () {
        //do something
    };
};

var a = new A();    // constructor function gets executed
                    // newly created object gets an 'x' property
                    // which is a function
a.x();              // and can be called like this

在第二个示例中,您将向原型对象添加一个属性,所有使用a创建的实例都指向该属性。

var A = function () { };
A.prototype.x = function () {
    //do something
};

var a = new A();    // constructor function gets executed
                    // which does nothing in this example

a.x();              // you are trying to access the 'x' property of an instance of 'A'
                    // which does not exist
                    // so JavaScript looks for that property in the prototype object
                    // that was defined using the 'prototype' property of the constructor

总之,在第一个示例中,函数的副本被分配给每个实例。在第二个示例中,所有实例共享函数的单个副本。

其他回答

想想静态类型的语言,原型上的东西是静态的,而这上面的东西是与实例相关的。

每个对象都链接到原型对象。当试图访问不存在的属性时,JavaScript将在对象的原型对象中查找该属性,如果该属性存在,则返回该属性。

函数构造函数的prototype属性引用使用new时使用该函数创建的所有实例的原型对象。


在第一个示例中,您将向使用a函数创建的每个实例添加属性x。

var A = function () {
    this.x = function () {
        //do something
    };
};

var a = new A();    // constructor function gets executed
                    // newly created object gets an 'x' property
                    // which is a function
a.x();              // and can be called like this

在第二个示例中,您将向原型对象添加一个属性,所有使用a创建的实例都指向该属性。

var A = function () { };
A.prototype.x = function () {
    //do something
};

var a = new A();    // constructor function gets executed
                    // which does nothing in this example

a.x();              // you are trying to access the 'x' property of an instance of 'A'
                    // which does not exist
                    // so JavaScript looks for that property in the prototype object
                    // that was defined using the 'prototype' property of the constructor

总之,在第一个示例中,函数的副本被分配给每个实例。在第二个示例中,所有实例共享函数的单个副本。

当您使用原型时,函数只会被加载到内存中一次(取决于您创建的对象数量),并且您可以随时重写该函数。

使用this而不是prototype的最终问题是,当重写方法时,基类的构造函数仍将引用重写的方法。考虑一下:

BaseClass = function() {
    var text = null;

    this.setText = function(value) {
        text = value + " BaseClass!";
    };

    this.getText = function() {
        return text;
    };

    this.setText("Hello"); // This always calls BaseClass.setText()
};

SubClass = function() {
    // setText is not overridden yet,
    // so the constructor calls the superclass' method
    BaseClass.call(this);

    // Keeping a reference to the superclass' method
    var super_setText = this.setText;
    // Overriding
    this.setText = function(value) {
        super_setText.call(this, "SubClass says: " + value);
    };
};
SubClass.prototype = new BaseClass();

var subClass = new SubClass();
console.log(subClass.getText()); // Hello BaseClass!

subClass.setText("Hello"); // setText is already overridden
console.log(subClass.getText()); // SubClass says: Hello BaseClass!

对比:

BaseClass = function() {
    this.setText("Hello"); // This calls the overridden method
};

BaseClass.prototype.setText = function(value) {
    this.text = value + " BaseClass!";
};

BaseClass.prototype.getText = function() {
    return this.text;
};

SubClass = function() {
    // setText is already overridden, so this works as expected
    BaseClass.call(this);
};
SubClass.prototype = new BaseClass();

SubClass.prototype.setText = function(value) {
    BaseClass.prototype.setText.call(this, "SubClass says: " + value);
};

var subClass = new SubClass();
console.log(subClass.getText()); // SubClass says: Hello BaseClass!

如果你认为这不是一个问题,那么这取决于你是否能在没有私人变量的情况下生活,以及你是否有足够的经验在看到泄漏时知道泄漏。此外,必须将构造函数逻辑放在方法定义之后是不方便的。

var A = function (param1) {
    var privateVar = null; // Private variable

    // Calling this.setPrivateVar(param1) here would be an error

    this.setPrivateVar = function (value) {
        privateVar = value;
        console.log("setPrivateVar value set to: " + value);

        // param1 is still here, possible memory leak
        console.log("setPrivateVar has param1: " + param1);
    };

    // The constructor logic starts here possibly after
    // many lines of code that define methods

    this.setPrivateVar(param1); // This is valid
};

var a = new A(0);
// setPrivateVar value set to: 0
// setPrivateVar has param1: 0

a.setPrivateVar(1);
//setPrivateVar value set to: 1
//setPrivateVar has param1: 0

对比:

var A = function (param1) {
    this.setPublicVar(param1); // This is valid
};
A.prototype.setPublicVar = function (value) {
    this.publicVar = value; // No private variable
};

var a = new A(0);
a.setPublicVar(1);
console.log(a.publicVar); // 1

第一个示例仅更改该对象的接口。第二个示例更改该类的所有对象的接口。