In Javascript, the difference between 'Object.create' and 'new'

后端 未结 2 460
眼角桃花
眼角桃花 2021-02-03 14:25

I think the difference has clicked in my head, but I\'d just like to be sure.

On the Douglas Crockford page Prototypal Inheritance in JavaScript, he says

2条回答
  •  猫巷女王i
    2021-02-03 14:57

    EDIT: This answer was originally a response to @jordancpaul's answer, which he has since corrected. I will leave the portion of my answer that helps explain the important difference between prototype properties and instance properties:

    In some cases, properties are shared between all instances and you need to be very careful whenever you're declaring properties on the prototype. Consider this example:

    Person.prototype.favoriteColors = []; //Do not do this!

    Now, if you create a new Person instance using either Object.create or new, it doesn't work as you might expect...

    var jim = new Person("Jim",13);
    jim.favoriteColors.push('red');
    var tim = new Person("Tim",14);
    tim.favoriteColors.push('blue');
    
    console.log(tim.favoriteColors); //outputs an array containing red AND blue!
    

    This doesn't mean you can't ever declare properties on the prototype, but if you do, you and every developer who works on your code needs to be aware of this pitfall. In a case like this, if you prefer declaring properties on the prototype for whatever reason, you could do:

    Person.prototype.favoriteColors = null

    And initialize it to an empty array in the constructor:

    var Person = function(name, age) {
        ...
        this.favoriteColors = [];
    }
    

    The general rule when using this method is that default values for simple literal properties (strings, numbers, booleans) can be set on the prototype directly, but any property that inherits from Object (including arrays and dates) should be set to null and then initialized in the constructor.

    The safer way is to only declare methods on the prototype, and always declare properties in the constructor.

    Anyway, the question was about Object.create...

    The first argument passed to Object.create is set as the prototype of the new instance. A better usage would be:

    var person = {
        initialize: function(name, age) {
            this.name = name;
            this.age = age;
            return this;
        },
    
        toString: function() {
            return this.name + ', ' + this.age;
        }
    };
    
    var tim = Object.create(person).initialize("Tim",14);
    

    Now the output will be the same as in your first example.

    As you can see, it's a different philosophical approach from the more classical style of OOP in Javascript. With Object.create, the emphasis is on creating new objects from existing objects, rather than on the constructor. Initialization then becomes a separate step.

    Personally I have mixed feelings about the Object.create approach; it's very nice for inheritance because of the second parameter that you can use to add additional properties to an existing prototype, but it also is more verbose and makes it so instanceof checks no longer work (the alternative in this example would be to check person.isPrototypeOf(tim)).

    The main reason I say Object.create is verbose is because of the second parameter, but there are some useful libraries out there that address that:

    https://github.com/Gozala/selfish

    https://github.com/Raynos/pd

    (and others)

    I hope that was more enlightening than confusing!

提交回复
热议问题