Javascript object members that are prototyped as arrays become shared by all class instances

前端 未结 3 757
日久生厌
日久生厌 2020-11-22 08:40

Has anyone noticed this behavior before? This really threw me off... I would have expected prototyped arrays to be private to each class instance rather than shared between

相关标签:
3条回答
  • 2020-11-22 09:17

    The behaviour is correct. [] is tranlated to new Array() in runtime, but only one such array is ever created.

    In other words, Obj.prototype = {...} is executed just like any other assigment.

    0 讨论(0)
  • 2020-11-22 09:19

    The prototype of an object is just an object. The prototype properties are shared between all objects that inherit from that object. No copies of the properties are made if you create a new instance of a "class" (classes don't exist anyway in JS), i.e. an object which inherits from the prototype.

    It only makes a difference on how you use the these inherited properties:

    function Foo() {}
    
    Foo.prototype = {
        array: [],
        func: function() {}
    }
    
    a = new Foo();
    b = new Foo();
    
    a.array.push('bar');
    console.log(b.array); // prints ["bar"]
    
    b.func.bar = 'baz';
    console.log(a.func.bar); // prints baz
    

    In all these cases you are always working with the same object.

    But if you assign a value to a property of the object, the property will be set/created on the object itself, not its prototype, and hence is not shared:

    console.log(a.hasOwnProperty('array')); // prints false
    console.log(a.array); // prints ["bar"]
    a.array = ['foo'];
    console.log(a.hasOwnProperty('array')); // prints true
    console.log(a.array); // prints ["foo"]
    console.log(b.array); // prints ["bar"]
    

    If you want to create own arrays for each instance, you have to define it in the constructor:

    function Foo() {
        this.array = [];
    }
    

    because here, this refers to the new object that is generated when you call new Foo().

    The rule of thumb is: Instance-specific data should be assigned to the instance inside the constructor, shared data (like methods) should be assigned to the prototype.


    You might want to read Details of the object model which describes differences between class-based vs. prototype-based languages and how objects actually work.

    Update:

    You can access the prototype of an object via Object.getPrototypeOf(obj) (might not work in very old browsers), and Object.getPrototypeOf(a) === Object.getPrototypeOf(b) gives you true. It is the same object, also known as Foo.prototype.

    0 讨论(0)
  • 2020-11-22 09:37

    When you do var exp1 = new C(), JavaScript sets exp1.[[Prototype]] = C.prototype. When you then access properties of the instance, JavaScript first checks whether they exist on that object directly, and if not, it looks in [[Prototype]]. This means that all the stuff you define in prototype is effectively shared by all instances, and you can even later change parts of prototype and have the changes appear in all existing instances.

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