0

阅读在 JavaScript 中可以使用哪些技术来定义类,以及它们的取舍是什么?在stackoverflow上我知道我可以通过定义一个类

方法一:

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

并在原型中添加函数,以避免每次实例化时重新创建成员函数。像

Person.prototype.speak = function(){
   alert("my name is" + this.name);
}

并通过创建其实例

var person = new Person("Bob", "M"); 

我认为没有 new 关键字就可以创建相同的对象

方法二:

var Person = function (name, gender) {

    return {name:name, gender:gender}; 

}

person  = Person("Bob", "M");

第二种方法是否与第一种方法完全相同?另外,如果是这样,我将如何在第二种方法中模拟通过原型添加功能(正如我们在方法 1 中看到的那样)

4

4 回答 4

5

不,方法 2 != 方法 1。第二种方法是创建一个新的匿名对象,其原型指向 ,Object.prototype而第一种方法是创建一个新对象,其原型指向Person.prototype

在伪代码中:

// Method #1
function Person(name, gender) {
    // The magic JS does *for us* (but *only* when invoked with `new`)
    var this = {};
    // __proto__ is the *internal* prototype reference
    // It's not required to be accessible unless you're in an ES6 environment.
    this.__proto__ = Person.prototype;

    // Person.prototype is also created by JS for us
    // and provided with a reference (among other things)
    // to this function as prototype.constructor.

    // Our stuff
    this.name = name;
    this.gender = gender;

    // More JS magic
    return this;
}

// Method #2
function Person(name, gender) {
    // Just our stuff - no magic JS goodness here
    return {
        name: name, gender: gender
    };
}
于 2013-07-02T18:32:05.387 回答
3

正如 Sean Vieira 所解释的,第一种方法与第二种方法不同。在第一种方法中,实例继承自Person.prototype. 在第二种方法中,实例直接继承自Object.prototype.

方法一:

        null
         ^
         |
         | __proto__
         |
+------------------+
| Object.prototype |
+------------------+
         ^
         |
         | __proto__
         |
+------------------+
| Person.prototype |
+------------------+
         ^
         |
         | __proto__
         |
+------------------+
|      person      |
+------------------+

方法二:

        null
         ^
         |
         | __proto__
         |
+------------------+
| Object.prototype |
+------------------+
         ^
         |
         | __proto__
         |
+------------------+
|      person      |
+------------------+

有趣的是,上面的图表向您展示了对象继承自JavaScript 中的其他对象,而不是构造函数。因此,当您创建new Person实例时,它继承自Person.prototype,而不是Person其自身。

这个相关信息如何?对于初学者,它表明您不需要创建构造函数来创建对象的实例。相反,您可以直接创建原型对象,如下所示:

var person = {
    create: function (name, gender) {
        var person = Object.create(this);
        person.gender = gender;
        person.name = name;
        return person;
    },
    speak: function () {
        alert("My name is " + this.name + ".");
    }
};

在上面的例子person中等价于Person.prototype。您现在可以创建person如下实例:

var bob = person.create("Bob", "M");

的原型链bob将如下所示:

        null
         ^
         |
         | __proto__
         |
+------------------+
| Object.prototype |
+------------------+
         ^
         |
         | __proto__
         |
+------------------+
|      person      |
+------------------+
         ^
         |
         | __proto__
         |
+------------------+
|       bob        |
+------------------+

那么为什么要创建这样的对象呢?

  1. 它看起来更干净。一切都封装在一个对象字面量中。
  2. 对象继承自对象更容易理解。不需要构造函数。
  3. 您不需要使用new来创建实例。这解决很多问题。_

有关此模式的更多信息,请阅读我关于“为什么原型继承很重要”的博文。

于 2013-07-03T02:42:08.460 回答
0

您的示例在访问属性方面实现了相同的目标,但它们并不相同,因为第一种方法具有基本Object原型。你的第二个问题的答案是:

function Person( name, gender ){
   return {
     name: name,
     gender: gender,
     speak: function(){
        alert("my name is" + this.name);
     }
   };
}

这里没有原型。该函数被烘焙到对象文字中。使用文字而不是原型的唯一价值是创建一个闭包,这样您就可以拥有私有变量,例如:

function Person( name, gender ){
   return {
     speak: function(){
        alert("my name is" + name);
     }
   };
}
于 2013-07-02T18:27:26.627 回答
0

也许这个答案可以解释更多关于构造函数、继承、私有变量和覆盖方法的信息:原型继承 - 编写

其他答案已经解决了您的问题;将对象创建为对象字面量{prop:val,method:function(){}}并使用构造函数创建对象var MyObject=function(){this.prop=val};MyObject.prototype.method=function(){}

于 2013-07-03T01:31:49.153 回答