我最近偶然发现了JavaScript中的object .create()方法,并试图推断它与使用new SomeFunction()创建对象的新实例有何不同,以及当您想要使用其中一个而不是另一个时。

考虑下面的例子:

var test = { val: 1, func: function() { return this.val; } }; var testA = Object.create(test); testA.val = 2; console.log(test.func()); // 1 console.log(testA.func()); // 2 console.log('other test'); var otherTest = function() { this.val = 1; this.func = function() { return this.val; }; }; var otherTestA = new otherTest(); var otherTestB = new otherTest(); otherTestB.val = 2; console.log(otherTestA.val); // 1 console.log(otherTestB.val); // 2 console.log(otherTestA.func()); // 1 console.log(otherTestB.func()); // 2

请注意,在这两种情况下观察到相同的行为。在我看来,这两种情况的主要区别是:

在object .create()中使用的对象实际上形成了新对象的原型,而在new Function()中声明的属性/函数不形成原型。 不能像使用函数式语法一样使用Object.create()语法创建闭包。考虑到JavaScript的词法(相对于块)类型范围,这是合乎逻辑的。

上述说法正确吗?我是不是遗漏了什么?什么时候你会使用其中一种而不是另一种?

编辑:链接到上述代码示例的jsfiddle版本:http://jsfiddle.net/rZfYL/


当前回答

function Test(){
    this.prop1 = 'prop1';
    this.prop2 = 'prop2';
    this.func1 = function(){
        return this.prop1 + this.prop2;
    }
};

Test.prototype.protoProp1 = 'protoProp1';
Test.prototype.protoProp2 = 'protoProp2';
var newKeywordTest = new Test();
var objectCreateTest = Object.create(Test.prototype);

/* Object.create   */
console.log(objectCreateTest.prop1); // undefined
console.log(objectCreateTest.protoProp1); // protoProp1 
console.log(objectCreateTest.__proto__.protoProp1); // protoProp1

/* new    */
console.log(newKeywordTest.prop1); // prop1
console.log(newKeywordTest.__proto__.protoProp1); // protoProp1

简介:

1)用new关键字有两点要注意;

A)函数被用作构造函数

b)函数。原型对象被传递给__proto__属性…或者在不支持__proto__的地方,它是新对象寻找属性的第二个地方

2)使用object .create(obj.prototype)你正在构造一个对象(obj.prototype)并将其传递给预期的对象。不同的是,现在new object的__proto__也指向obj。原型(请参考ans by xj9)

其他回答

下面是两个调用内部发生的步骤: (提示:唯一的区别是在步骤3)


新的测试():

创建新的Object() obj obj。__proto__ to Test.prototype return Test.call(obj) || obj; //通常返回obj,但JS中的构造函数可以返回一个值


对象。创建(测试。原型)

创建新的Object() obj obj。__proto__ to Test.prototype 返回obj;


基本上就是Object。Create不执行构造函数。

区别在于所谓的“伪经典vs.原型继承”。建议在代码中只使用一种类型,不要混合使用两种类型。

在伪经典继承中(使用"new"操作符),假设您首先定义了一个伪类,然后从该类创建对象。例如,定义一个伪类“Person”,然后从“Person”创建“Alice”和“Bob”。

在原型继承中(使用Object.create),您直接创建一个特定的人“Alice”,然后使用“Alice”作为原型创建另一个人“Bob”。这里没有“阶级”;都是对象。

在内部,JavaScript使用“原型继承”;“伪古典”的方式只是一些糖。

查看这两种方法的比较。

object中使用的对象。create实际上形成了新对象的原型,而在new Function()形式中,声明的属性/函数不形成原型。

是的,对象。Create构建一个直接继承作为其第一个参数传递的对象的对象。

使用构造函数,新创建的对象继承自构造函数的原型,例如:

var o = new SomeConstructor();

在上面的例子中,o直接继承自SomeConstructor.prototype。

这里有一个不同,对象。你可以创建一个不继承任何东西的对象object .create(null);,另一方面,如果你设置SomeConstructor。原型= null;新创建的对象将继承object .prototype。

你不能用对象创建闭包。像使用函数式语法一样创建语法。考虑到JavaScript的词法(相对于块)类型范围,这是合乎逻辑的。

你可以创建闭包,例如使用属性描述符参数:

var o = Object.create({inherited: 1}, {
  foo: {
    get: (function () { // a closure
      var closured = 'foo';
      return function () {
        return closured+'bar';
      };
    })()
  }
});

o.foo; // "foobar"

注意,我说的是ECMAScript第5版对象。create方法,而不是Crockford's shim。

该方法已开始在最新的浏览器上本机实现,请检查此兼容性表。

内部对象。Create是这样做的:

Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
};

语法只是消除了JavaScript使用经典继承的错觉。

让我试着解释(更多在博客上):

When you write Car constructor var Car = function(){}, this is how things are internally: We have one {prototype} hidden link to Function.prototype which is not accessible and one prototype link to Car.prototype which is accessible and has an actual constructor of Car. Both Function.prototype and Car.prototype have hidden links to Object.prototype. When we want to create two equivalent objects by using the new operator and create method then we have to do it like this: Honda = new Car(); and Maruti = Object.create(Car.prototype). What is happening? Honda = new Car(); — When you create an object like this then hidden {prototype} property is pointed to Car.prototype. So here, the {prototype} of the Honda object will always be Car.prototype — we don't have any option to change the {prototype} property of the object. What if I want to change the prototype of our newly created object? Maruti = Object.create(Car.prototype) — When you create an object like this you have an extra option to choose your object's {prototype} property. If you want Car.prototype as the {prototype} then pass it as a parameter in the function. If you don't want any {prototype} for your object then you can pass null like this: Maruti = Object.create(null).

结论-通过使用方法对象。创建时你可以自由选择你的对象{prototype}属性。在new Car();中,你没有这样的自由。

面向对象JavaScript的首选方式:

假设我们有两个对象a和b。

var a = new Object();
var b = new Object();

现在,假设a有一些b也想访问的方法。为此,我们需要对象继承(只有当我们想要访问这些方法时,a才应该是b的原型)。如果我们检查a和b的原型,我们会发现它们共享Object.prototype原型。

Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).

问题-我们想要对象a作为b的原型,但是在这里我们用原型object .prototype创建了对象b。 解决方案- ECMAScript 5引入了Object.create(),可以轻松实现这种继承。如果我们像这样创建对象b:

var b = Object.create(a);

然后,

a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)

因此,如果你正在编写面向对象的脚本,那么object .create()对于继承非常有用。