Understanding the difference between Object.create() and new SomeFunction()

后端 未结 11 2498
失恋的感觉
失恋的感觉 2020-11-22 05:05

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

相关标签:
11条回答
  • 2020-11-22 05:57

    The object used in Object.create actually forms the prototype of the new object, where as in the new Function() form the declared properties/functions do not form the prototype.

    Yes, Object.create builds an object that inherits directly from the one passed as its first argument.

    With constructor functions, the newly created object inherits from the constructor's prototype, e.g.:

    var o = new SomeConstructor();
    

    In the above example, o inherits directly from SomeConstructor.prototype.

    There's a difference here, with Object.create you can create an object that doesn't inherit from anything, Object.create(null);, on the other hand, if you set SomeConstructor.prototype = null; the newly created object will inherit from Object.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.

    Well, you can create closures, e.g. using property descriptors argument:

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

    Note that I'm talking about the ECMAScript 5th Edition Object.create method, not the Crockford's shim.

    The method is starting to be natively implemented on latest browsers, check this compatibility table.

    0 讨论(0)
  • 2020-11-22 05:58

    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.

    0 讨论(0)
  • 2020-11-22 06:01

    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.

    0 讨论(0)
  • 2020-11-22 06:04

    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. ;)

    0 讨论(0)
  • 2020-11-22 06:04

    Object creation variants.


    Variant 1 : 'new Object()' -> Object constructor without arguments.

    var p1 = new Object(); // 'new Object()' create and return empty object -> {}
    
    var p2 = new Object(); // 'new Object()' create and return empty object -> {}
    
    console.log(p1); // empty object -> {}
    
    console.log(p2); // empty object -> {}
    
    // p1 and p2 are pointers to different objects
    console.log(p1 === p2); // false
    
    console.log(p1.prototype); // undefined
    
    // empty object which is in fact Object.prototype
    console.log(p1.__proto__); // {}
    
    // empty object to which p1.__proto__ points
    console.log(Object.prototype); // {}
    
    console.log(p1.__proto__ === Object.prototype); // true
    
    // null, which is in fact Object.prototype.__proto__
    console.log(p1.__proto__.__proto__); // null
    
    console.log(Object.prototype.__proto__); // null
    


    Variant 2 : 'new Object(person)' -> Object constructor with argument.

    const person = {
        name: 'no name',
        lastName: 'no lastName',
        age: -1
    }
    
    // 'new Object(person)' return 'person', which is pointer to the object ->
    //  -> { name: 'no name', lastName: 'no lastName', age: -1 }
    var p1 = new Object(person);
    
    // 'new Object(person)' return 'person', which is pointer to the object ->
    //  -> { name: 'no name', lastName: 'no lastName', age: -1 }
    var p2 = new Object(person);
    
    // person, p1 and p2 are pointers to the same object
    console.log(p1 === p2); // true
    console.log(p1 === person); // true
    console.log(p2 === person); // true
    
    p1.name = 'John'; // change 'name' by 'p1'
    p2.lastName = 'Doe'; // change 'lastName' by 'p2'
    person.age = 25; // change 'age' by 'person'
    
    // when print 'p1', 'p2' and 'person', it's the same result,
    // because the object they points is the same
    console.log(p1); // { name: 'John', lastName: 'Doe', age: 25 }
    console.log(p2); // { name: 'John', lastName: 'Doe', age: 25 }
    console.log(person); // { name: 'John', lastName: 'Doe', age: 25 }
    


    Variant 3.1 : 'Object.create(person)'. Use Object.create with simple object 'person'. 'Object.create(person)' will create(and return) new empty object and add property '__proto__' to the same new empty object. This property '__proto__' will point to the object 'person'.

    const person = {
            name: 'no name',
            lastName: 'no lastName',
            age: -1,
            getInfo: function getName() {
               return `${this.name} ${this.lastName}, ${this.age}!`;
        }
    }
    
    var p1 = Object.create(person);
    
    var p2 = Object.create(person);
    
    // 'p1.__proto__' and 'p2.__proto__' points to
    // the same object -> 'person'
    // { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
    console.log(p1.__proto__);
    console.log(p2.__proto__);
    console.log(p1.__proto__ === p2.__proto__); // true
    
    console.log(person.__proto__); // {}(which is the Object.prototype)
    
    // 'person', 'p1' and 'p2' are different
    console.log(p1 === person); // false
    console.log(p1 === p2); // false
    console.log(p2 === person); // false
    
    // { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
    console.log(person);
    
    console.log(p1); // empty object - {}
    
    console.log(p2); // empty object - {}
    
    // add properties to object 'p1'
    // (properties with the same names like in object 'person')
    p1.name = 'John';
    p1.lastName = 'Doe';
    p1.age = 25;
    
    // add properties to object 'p2'
    // (properties with the same names like in object 'person')
    p2.name = 'Tom';
    p2.lastName = 'Harrison';
    p2.age = 38;
    
    // { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
    console.log(person);
    
    // { name: 'John', lastName: 'Doe', age: 25 }
    console.log(p1);
    
    // { name: 'Tom', lastName: 'Harrison', age: 38 }
    console.log(p2);
    
    // use by '__proto__'(link from 'p1' to 'person'),
    // person's function 'getInfo'
    console.log(p1.getInfo()); // John Doe, 25!
    
    // use by '__proto__'(link from 'p2' to 'person'),
    // person's function 'getInfo'
    console.log(p2.getInfo()); // Tom Harrison, 38!
    


    Variant 3.2 : 'Object.create(Object.prototype)'. Use Object.create with built-in object -> 'Object.prototype'. 'Object.create(Object.prototype)' will create(and return) new empty object and add property '__proto__' to the same new empty object. This property '__proto__' will point to the object 'Object.prototype'.

    // 'Object.create(Object.prototype)' :
    // 1. create and return empty object -> {}.
    // 2. add to 'p1' property '__proto__', which is link to 'Object.prototype'
    var p1 = Object.create(Object.prototype);
    
    // 'Object.create(Object.prototype)' :
    // 1. create and return empty object -> {}.
    // 2. add to 'p2' property '__proto__', which is link to 'Object.prototype'
    var p2 = Object.create(Object.prototype);
    
    console.log(p1); // {}
    
    console.log(p2); // {}
    
    console.log(p1 === p2); // false
    
    console.log(p1.prototype); // undefined
    
    console.log(p2.prototype); // undefined
    
    console.log(p1.__proto__ === Object.prototype); // true
    
    console.log(p2.__proto__ === Object.prototype); // true
    


    Variant 4 : 'new SomeFunction()'

    // 'this' in constructor-function 'Person'
    // represents a new instace,
    // that will be created by 'new Person(...)'
    // and returned implicitly
    function Person(name, lastName, age) {
    
        this.name = name;
        this.lastName = lastName;
        this.age = age;
    
        //-----------------------------------------------------------------
        // !--- only for demonstration ---
        // if add function 'getInfo' into
        // constructor-function 'Person',
        // then all instances will have a copy of the function 'getInfo'!
        //
        // this.getInfo: function getInfo() {
        //  return this.name + " " + this.lastName + ", " + this.age + "!";
        // }
        //-----------------------------------------------------------------
    }
    
    // 'Person.prototype' is an empty object
    // (before add function 'getInfo')
    console.log(Person.prototype); // Person {}
    
    // With 'getInfo' added to 'Person.prototype',
    // instances by their properties '__proto__',
    // will have access to the function 'getInfo'.
    // With this approach, instances not need
    // a copy of the function 'getInfo' for every instance.
    Person.prototype.getInfo = function getInfo() {
        return this.name + " " + this.lastName + ", " + this.age + "!";
    }
    
    // after function 'getInfo' is added to 'Person.prototype'
    console.log(Person.prototype); // Person { getInfo: [Function: getInfo] }
    
    // create instance 'p1'
    var p1 = new Person('John', 'Doe', 25);
    
    // create instance 'p2'
    var p2 = new Person('Tom', 'Harrison', 38);
    
    // Person { name: 'John', lastName: 'Doe', age: 25 }
    console.log(p1);
    
    // Person { name: 'Tom', lastName: 'Harrison', age: 38 }
    console.log(p2);
    
    // 'p1.__proto__' points to 'Person.prototype'
    console.log(p1.__proto__); // Person { getInfo: [Function: getInfo] }
    
    // 'p2.__proto__' points to 'Person.prototype'
    console.log(p2.__proto__); // Person { getInfo: [Function: getInfo] }
    
    console.log(p1.__proto__ === p2.__proto__); // true
    
    // 'p1' and 'p2' points to different objects(instaces of 'Person')
    console.log(p1 === p2); // false
    
    // 'p1' by its property '__proto__' reaches 'Person.prototype.getInfo' 
    // and use 'getInfo' with 'p1'-instance's data
    console.log(p1.getInfo()); // John Doe, 25!
    
    // 'p2' by its property '__proto__' reaches 'Person.prototype.getInfo' 
    // and use 'getInfo' with 'p2'-instance's data
    console.log(p2.getInfo()); // Tom Harrison, 38!
    

    0 讨论(0)
提交回复
热议问题