什么时候在当前对象和原型上创建属性?
When is a property created on the current object VS a prototype?
我正在阅读谷歌的JS优化页面,并得到了这个部分:
将实例变量声明/初始化放在值类型为…的实例变量的原型上。这避免了每次调用构造函数时不必要地运行初始化代码。
我想,"等等,那你就不能改变实例中的值了"
但事实证明你可以,这让我很惊讶。
为什么当你改变一个原型提供给你的值时,它会在对象本身上被设置?
x = { one: 1 }
y = Object.create(x)
y.one // 1, of course
y.one++;
y.one // 2
x.one // 1! why isn't this 2?
定义此行为的规则是什么?
是不是左侧查找总是在最近的对象上,而右侧查找将遍历原型链?
如果是这样,这将适用于引用类型和值类型,但也许突变(y.arr.push(1)
)的诱惑太大了,因此Google建议只对值进行此操作?
这有点复杂。
右侧:查找原型链,找到第一个匹配的(无论是getter还是data属性),如果没有找到则返回undefined
左边:查找原型链,如果找到setter就使用它;否则,在对象本身设置一个数据值。
如果简单的赋值改变了原型,那将是可怕的。(想象一下,例如,如果你切掉你自己的一个千克重量,国际千克原型会自动改变重量,随之而来的是混乱。)
这是否意味着只有显式setter,而不仅仅是任何可编辑的属性?我能麻烦你找一个在原型之上有setter的例子和一个没有setter的例子吗?
var x = {
data: 1,
hidden: 1,
set accessor(val) {
this.hidden = val;
},
get accessor() {
return this.hidden;
}
};
var y = Object.create(x);
console.log("orig: x.data:", x.data, "; y.data:", y.data); // 1, 1
y.data = y.data + 1;
console.log("inc: x.data:", x.data, "; y.data:", y.data); // 1, 2
delete y.data; // removes y.data, so y.data is again looked up at x.data
console.log("del data: x.data:", x.data, "; y.data:", y.data); // 1, 1
console.log("----------");
console.log("orig: x.accessor:", x.accessor, "; y.accessor:", y.accessor); // 1, 1
y.accessor = y.accessor + 1;
console.log("inc: x.accessor:", x.accessor, "; y.accessor:", y.accessor); // 1, 2
console.log(" x.hidden:", x.accessor, "; y.hidden:", y.hidden); // 1, 2
delete y.accessor; // silent fail, y.accessor doesn't exist
console.log("del acc: x.accessor:", x.accessor, "; y.accessor:", y.accessor); // 1, 2
console.log(" x.hidden:", x.hidden, "; y.hidden:", y.hidden); // 1, 2
delete y.hidden;
console.log("del hidden: x.accessor:", x.accessor, "; y.accessor:", y.accessor); // 1, 1
console.log(" x.hidden:", x.hidden, "; y.hidden:", y.hidden); // 1, 1
这里你可以看到的区别是,我们可以在y.data = ...
之后删除y.data
(数据属性),但是我们不能在y.accessor = ...
之后删除y.accessor
,因为它不存在——x.accessor
是用来设置y.hidden
的。
这是因为属性赋值([[Set]]内部方法)到达了原型对象x
上的属性,但接收器仍然是y
。然后,在y
上定义属性。x
的属性保持不变。
y.one = 2
是这样做的:
-
y.[[Set]]("one", 2, y)
被调用 - 由于
y
没有"one"
自己的属性,调用被重定向到父y.[[GetPrototypeOf]]()
,即x
。 -
x.[[Set]]("one", 2, y)
被调用。 - 由于
x
有"one"
自己的属性,这是一个数据属性(即不是getter/setter访问器),并且是可写的,因此在y
上定义了一个新属性 -
y.[[DefineOwnProperty]]("one", PropertyDescriptor{[[Value]]: 2})
如果你不希望这样,你可以使用自定义访问器:
var one = 1;
var x = {
get one() {
return one;
},
set one(value) {
one = value;
}
};
var y = Object.create(x);
console.log(y.one); // 1
y.one++;
console.log(y.one); // 2
console.log(x.one); // 2
- 创建属性值数组,其中属性名称以特定字符串结尾
- Do let语句在全局对象上创建属性
- 如何在 javascript 中为策略设计模式创建属性
- 如何在 JavaScript 中基于另一个对象动态创建属性和对象
- 在运行时为对象创建属性
- Javascript对象:动态创建属性和属性名称
- Javascript对象属性-如果不存在,则创建属性
- 如何在使用纯js创建属性时执行某些操作
- 自动创建属性不起作用
- TypeError:无法创建属性'mapTypeId'在字符串'无法加载映射'流星错误
- 可以在任何地方用Javascript创建属性吗?
- 什么时候在当前对象和原型上创建属性?
- 在文字对象中创建属性
- 使用JSON从对象数组创建属性数组
- 如何创建属性
- 如何使用JavaScript在SVG中创建属性
- 当ngAnnotate说“不能创建属性'$methodName'..”是什么意思?
- 无法创建属性'选择'在字符串'信息技术'angularjs
- 在ng模型中动态创建属性
- 如何在ng重复作用域内创建属性