【Web前端问题】js中原型对象的writable为什么会影响到实例对象?
我定义了一个Person构造函数
function Person(){}
然后定义了一个对象
var per1 = new Person();
在Person原型对象中定义了一个属性like,并将可写性设置为false
Object.defineProperty(Person.prototype,"like",{ value:"eating",
enumerable:false,
writable:false,
configurable:true
});
修改per1的like值
per1的like属性不可更改,这是为什么?原型对象的writable为何会影响到实例对象上?
随后我又将原型对象的writable置为true
Object.defineProperty(Person.prototype,"like",{ value:"eating",
enumerable:false,
writable:true,
configurable:true
});
per1的like属性值可更改了,随后我再将原型对象的writable置为false
Object.defineProperty(Person.prototype,"like",{ value:"eating",
enumerable:false,
writable:false,
configurable:true
});
而per1的like属性又不再受到原型writable的影响,此时运行如下
那么原型对象的writable到底是如何实例对象的,为什么会产生如上效果
回答:
JS中属性的读取和设置是不同的
读取的时候按实例对象->原型对象->原型对象..的顺序查找,都找不到返回undefined
而赋值时,首先在实例对象中寻找是否有属性,
如果没有这个属性,那么就把这个属性添加到实例对象上;
但是有例外,如果其原型链中有这个属性,但其为只读,那么就不会实例对象上添加这个新的属性,赋值操作无效
如果其原型链中有这个属性,但其不为只读,那么就会在实例对象上添加这个新的属性
如果能再实例对象上找到这个属性,那么直接对此属性赋值(也不一定看其是否只读)
function Person(){}
var per1 = new Person();
Object.defineProperty(Person.prototype,"like",{
value:"eating",
enumerable:false,
writable:false,
configurable:true
});
like属性是定义在其原型上的并且其只读,那么
per1.like的任何修改都是无效的,也不会在当前实例对象上添加like属性
Object.defineProperty(Person.prototype,"like",{ value:"eating",
enumerable:false,
writable:true,
configurable:true
});
per1.like的可被修改,在当前实例对象上添加了属性like
per1.like=“gogog”;for(var prop in per1){
if(per1.hasOwnProperty(prop)){
console.log(prop);//输出like
}
}
此时你再
Object.defineProperty(Person.prototype,"like",{ value:"eating",
enumerable:false,
writable:false,
configurable:true
});
此时per1的实例上已经有了like属性,那就直接修改喽
回答:
首先你要明白,原型上的方法和属性是被所有实例共同拥有的。
而构造函数上的方法和属性则是每个实例独自拥有。
当实例调用一个方法或者属性时,首先会查找构造函数是否具有该方法或者属性,如果没有,则会调用原型上的方法或者属性。
因此,实例如果调用的是原型的属性,那你修改了原型上like的writable,那访问肯定会受到影响嘛。
至于你试图第二次将like的writeable设置为false时,使用如下方法判断
Object.getOwnPropertyDescriptor(per1, 'like');// 结果 Object {value: "bbb", writable: true, enumerable: true, configurable: true}
发现并没有修改成功。具体原因暂时未知。
回答:
由于你上面的代码片实在是太多了,我就按你的意思也一个类似的代码来解释吧
在定义实例上的属性时是不查找原型链的,但是有一个特殊的,也就是你说的第一种情况,当原型上的该属性的writable为false并且当前实例对象没有该属性时,由于该属性被规定好了是不可以写的,那么就不能更改这个值,所以就是不能再对实例对象定义该属性了,说点白话就是:实例对象一开始从原型上继承来了该属性,告诉了对象这个属性不可以写,所以在给对象定义时就出现了你说的第一种情况
下面俩种情况的代码:
function Foo() {}; var obj = new Foo();
Object.defineProperty(Foo.prototype,"x",{
value: "zp",
writable: true
});
obj.x = "12345";
console.log(obj.x);
Object.defineProperty(Foo.prototype,"x",{
value: "zp",
writable: false
});
console.log(obj.x);
obj.x = 20;
console.log(obj.x);
简单来说,由于你一开始把原型上的writable属性写为了true,所以改变实例属性不查找原型链,下面你把原型上的该属性又改成了不可写,但是不影响实例对象的这个属性,因为这个属性是实例对象上的,它是可写的,所以可以更改
以上是 【Web前端问题】js中原型对象的writable为什么会影响到实例对象? 的全部内容, 来源链接: utcz.com/a/142892.html