Understanding the difference between Object.create

2018-12-31 08:12发布

I recently stumbled upon the Object.create() method in JavaScript, and am trying to deduce how it is different from creating a new instance of an object with new SomeFunction(), and when you would want to use one over the other.

Consider the following example:

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

Notice that the same behaviour is observed in both cases. It seems to me that the primary differences between these two scenarios are:

  • The object used in Object.create() actually forms the prototype of the new object, whereas in the new Function() from the declared properties/functions do not form the prototype.
  • You cannot create closures with the Object.create() syntax as you would with the functional syntax. This is logical given the lexical (vs block) type scope of JavaScript.

Are the above statements correct? And am I missing something? When would you use one over the other?

EDIT: link to jsfiddle version of above code sample: http://jsfiddle.net/rZfYL/

10条回答
还给你的自由
2楼-- · 2018-12-31 08:45

Very simply said, new X is Object.create(X.prototype) with additionally running the constructor function. (And giving the constructor the chance to return the actual object that should be the result of the expression instead of this.)

That’s it. :)

The rest of the answers are just confusing, because apparently nobody else reads the definition of new either. ;)

查看更多
不流泪的眼
3楼-- · 2018-12-31 08:45

Let me try to explain (more on Blog) :

  1. When you write Car constructor var Car = function(){}, this is how things are internally: A diagram of prototypal chains when creating javascript objects 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.
  2. 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).A diagram of prototypal chains for differing object creation methods 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).

Conclusion — By using the method Object.create you have the freedom to choose your object {prototype} property. In new Car();, you don't have that freedom.

Preferred way in OO JavaScript :

Suppose we have two objects a and b.

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

Now, suppose a has some methods which b also wants to access. For that, we require object inheritance (a should be the prototype of b only if we want access to those methods). If we check the prototypes of a and b then we will find out that they share the prototype Object.prototype.

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

Problem — we want object a as the prototype of b, but here we created object b with the prototype Object.prototype. Solution — ECMAScript 5 introduced Object.create(), to achieve such inheritance easily. If we create object b like this:

var b = Object.create(a);

then,

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

So, if you are doing object oriented scripting then Object.create() is very useful for inheritance.

查看更多
冷夜・残月
4楼-- · 2018-12-31 08:46

Accordingly to this answer and to this video new keyword does next things:

  1. Creates new object.

  2. Links new object to constructor function (prototype).

  3. Makes this variable point to the new object.

  4. Executes constructor function using the new object and implicit perform return this;

  5. Assigns constructor function name to new object's property constructor.

Object.create performs only 1st and 2nd steps!!!

查看更多
零度萤火
5楼-- · 2018-12-31 08:50

Here are the steps that happen internally for both calls:
(Hint: the only difference is in step 3)


new Test():

  1. create new Object() obj
  2. set obj.__proto__ to Test.prototype
  3. return Test.call(obj) || obj; // normally obj is returned but constructors in JS can return a value

Object.create( Test.prototype )

  1. create new Object() obj
  2. set obj.__proto__ to Test.prototype
  3. return obj;

So basically Object.create doesn't execute the constructor.

查看更多
千与千寻千般痛.
6楼-- · 2018-12-31 08:51

This:

var foo = new Foo();

and

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

are quite similar. One important difference is that new Foo actually runs constructor code, whereas Object.create will not execute code such as

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

Note that if you use the two-parameter version of Object.create() then you can do much more powerful things.

查看更多
笑指拈花
7楼-- · 2018-12-31 08:53

Internally Object.create does this:

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

The syntax just takes away the illusion that JavaScript uses Classical Inheritance.

查看更多
登录 后发表回答