person1作为一个实例,为什么可以改变原型里面的内容?这中间发生了什么?能不能从内存角度解释一下。。
认证高级PHP讲师
默认情况下,实例的原型就是它的构造函数的prototype所引用的对象。也就是说
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构造函数),直到顶端。
friends
书上的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认为这是声明私有变量操作,原有的公有属性不会改变
默认情况下,实例的原型就是它的构造函数的
prototype
所引用的对象。也就是说person1.__proto__ === person2.__proto__ === Person.prototype
这3者是同一个对象。
公有属性和私有属性
Person作为一个类,会有自己的一些公有属性和私有属性,你可以将prototype理解成这个类的公有属性,既然是公有的,那就是别人也能使用并且改变的。person1和person2都具有Person这个类的公有方法和属性,当person1改变了公有属性,另一个也实例person2的属性值也改变了。从内存的角度来讲,公有属性在内存里的就只有一个地址,前者(person1)操作完了,后者(person2)去读取的时候自然就是刚刚改完的。
为了避免这种情况,就应该把不想被共享的属性私有化,如下代码:
补充一句,属性的查找是基于原型链的,person1有自己的私有属性
friends
也有公有属性friends
,取值的时候先查找有没有私有属性,再去查找公有属性,如果公有属性也没有,就继续往上找(Object构造函数),直到顶端。基础类型的值的操作和引用类型的值的操作
书上的Demo中friends是数组,也就是引用类型的对象,push是这个数组具有的一个方法,所以调用push方法的时候并不会改变这个对象的内存地址。如果你是直接
赋值
,实际上是定义了私有属性:结论
书上的demo,因为是person1.friends.push,所以friends一定是具有push方法的,而公有属性'friends'恰恰具有这个方法,也即是先执行了查找操作。
对于上面的第二个demo,由于是赋值操作,改变了内存空间,Javascript认为这是声明私有变量操作,原有的公有属性不会改变