我最近偶然发现了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/


当前回答

这样的:

var foo = new Foo();

and

var foo = Object.create(Foo.prototype);

非常相似。一个重要的区别是,new Foo实际上运行构造函数代码,而Object。创建将不会执行诸如

function Foo() {
    alert("This constructor does not run with Object.create");
}

请注意,如果使用Object.create()的双参数版本,则可以执行更强大的操作。

其他回答

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

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

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

这样的:

var foo = new Foo();

and

var foo = Object.create(Foo.prototype);

非常相似。一个重要的区别是,new Foo实际上运行构造函数代码,而Object。创建将不会执行诸如

function Foo() {
    alert("This constructor does not run with Object.create");
}

请注意,如果使用Object.create()的双参数版本,则可以执行更强大的操作。

根据这个答案和这个视频,new关键字做了下面的事情:

创建新对象。 将新对象链接到构造函数(原型)。 使此变量指向新对象。 使用new对象执行构造函数,隐式执行返回this; 将构造函数函数名赋给新对象的属性构造函数。

对象。Create只执行第1和第2步!

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。

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

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

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()对于继承非常有用。