首页 > 关于js原型中引用类型的问题?

关于js原型中引用类型的问题?

person1作为一个实例,为什么可以改变原型里面的内容?这中间发生了什么?能不能从内存角度解释一下。。


默认情况下,实例的原型就是它的构造函数的prototype所引用的对象。也就是说

person1.__proto__ === person2.__proto__ === Person.prototype

这3者是同一个对象。


公有属性和私有属性

Person作为一个类,会有自己的一些公有属性和私有属性,你可以将prototype理解成这个类的公有属性,既然是公有的,那就是别人也能使用并且改变的。person1和person2都具有Person这个类的公有方法和属性,当person1改变了公有属性,另一个也实例person2的属性值也改变了。从内存的角度来讲,公有属性在内存里的就只有一个地址,前者(person1)操作完了,后者(person2)去读取的时候自然就是刚刚改完的。
为了避免这种情况,就应该把不想被共享的属性私有化,如下代码:

function Person(friends) {
    if ( friends )
        this.friends = friends;
}

Person.prototype = {
    constructor: Person,

    name: 'Nicholas',

    age: '29',

    job: 'Software Engineer',

    friends: ['Shelby', 'Counrt'],

    sayName: function() {
        alert(this.name);
    }
};

var person1 = new Person(['Van']);
var person2 = new Person();

person1.friends.push("Van");

console.log(person1.friends);//['Van', 'Van']
console.log(person2.friends);//['Shelby', 'Counrt']

补充一句,属性的查找是基于原型链的,person1有自己的私有属性friends也有公有属性friends,取值的时候先查找有没有私有属性,再去查找公有属性,如果公有属性也没有,就继续往上找(Object构造函数),直到顶端。

基础类型的值的操作和引用类型的值的操作

书上的Demo中friends是数组,也就是引用类型的对象,push是这个数组具有的一个方法,所以调用push方法的时候并不会改变这个对象的内存地址。如果你是直接赋值,实际上是定义了私有属性:

function Person() {
    
}

Person.prototype = {
    constructor: Person,

    name: 'Nicholas',

    age: '29',

    job: 'Software Engineer',

    friends: ['Shelby', 'Counrt'],

    sayName: function() {
        alert(this.name);
    }
};

var person1 = new Person(['Van']);
var person2 = new Person();

person1.friends = "Van";

console.log(person1);// Person {friends: 'Van'}
console.log(person2);// Person {}

结论

书上的demo,因为是person1.friends.push,所以friends一定是具有push方法的,而公有属性'friends'恰恰具有这个方法,也即是先执行了查找操作。
对于上面的第二个demo,由于是赋值操作,改变了内存空间,Javascript认为这是声明私有变量操作,原有的公有属性不会改变

【热门文章】
【热门文章】