HTML片段
<div id="container">
<span class="no"></span>
<span class="yes"></span>
<span class="no"></span>
<span class="no"></span>
</div>
Run Code Online (Sandbox Code Playgroud)
因此,一个getter会返回一个元素.yes并提供延迟的评估(我认为这是术语,对吧?
class Something{
constructor(){
this.elem = container;
}
get childYes(){
let span = this.elem.querySelector(".yes");
this.childYes = span;//Cannot set property clientName of #<Docum> which has only a getter
return span;
}
}
var object = new Something();
console.log(object.childYes);
Run Code Online (Sandbox Code Playgroud)
但是,如果我添加一个空的setter,它可以正常工作:
class Something{
constructor(){
this.elem = container;
}
get childYes(){
let span = this.elem.querySelector(".yes");
this.childYes = span;
return span;
}
set childYes(a){};
}
var object = new Something();
console.log(object.childYes); // <span class="yes"></span>
Run Code Online (Sandbox Code Playgroud)
我在那里不需要二传手,浏览器到底要我做什么?
无法设置
#<Docum>仅具有吸气剂的属性clientName
通过this.childYes = ...定义为访问器的属性,您正在尝试使用setter。要在实例上定义属性,请使用Object.defineProperty:
get childYes(){
let span = this.elem.querySelector(".yes");
Object.defineProperty(this, "childYes", {
value: span
});
return span;
}
Run Code Online (Sandbox Code Playgroud)
get childYes(){
let span = this.elem.querySelector(".yes");
Object.defineProperty(this, "childYes", {
value: span
});
return span;
}
Run Code Online (Sandbox Code Playgroud)
class Something{
constructor(){
this.elem = container;
}
get childYes(){
console.log("Getter ran");
let span = this.elem.querySelector(".yes");
Object.defineProperty(this, "childYes", {
value: span
});
return span;
}
}
var object = new Something();
console.log(object.childYes); // Runs the getter
console.log(object.childYes); // Uses the data propertyRun Code Online (Sandbox Code Playgroud)
在评论中,您询问:
因此,如果我错了,请纠正我:在调用object.childYes之后,程序首先查找
.childYes对象的自身属性;失败 去原型;找到吸气剂 开始执行吸气剂,当该行this.childYes = span;出现时,程序在原型中“在这里”寻找它并失败,对吗?
不是因为this.childYes = span;行在哪里,而是因为那是对的。当您分配给对象属性时,将发生什么取决于该属性是否存在于对象或其原型上,如果存在,取决于该属性是数据属性还是访问器属性:
在原始代码中,您结束了上面的步骤3.2,因为该属性在原型上作为访问器属性存在。
这是这些各种情况的示例:
<div id="container">
<span class="no"></span>
<span class="yes"></span>
<span class="no"></span>
<span class="no"></span>
</div>Run Code Online (Sandbox Code Playgroud)
"use strict";
// A function to tell us if an object has a property and, if so
// what kind of property it is
function getPropertyType(obj, propName) {
const descr = Object.getOwnPropertyDescriptor(obj, propName);
if (!descr) {
return "none";
}
if (descr.hasOwnProperty("get") || descr.hasOwnProperty("set")) {
return "accessor";
}
if (descr.hasOwnProperty("value") || descr.hasOwnProperty("writable")) {
return `data (${descr.value})`;
}
return "generic"; // Unlikely, but the spec allows for it
}
// An object to use as a prototype
const proto = {
dataProperty1: "dataProperty1 value",
_readWrite: "readWriteAccessor default value",
get readWriteAccessor() {
return this._readWrite;
},
set readWriteAccessor(value) {
this._readWrite = value;
},
get readOnlyAccessor() {
return "readOnlyAccessor value";
}
};
// Create an object using `proto` as its prototype
const obj = Object.create(proto);
console.log(`obj dataProperty2: ${getPropertyType(obj, "dataProperty2")}`);
console.log(`proto dataProperty2: ${getPropertyType(proto, "dataProperty2")}`);
console.log(`--- Before obj.dataProperty1 = "dataProperty1 updated";`);
console.log(`obj dataProperty1: ${getPropertyType(obj, "dataProperty1")}`);
console.log(`proto dataProperty1: ${getPropertyType(proto, "dataProperty1")}`);
obj.dataProperty1 = "dataProperty1 updated";
console.log(`--- After obj.dataProperty1 = "dataProperty1 updated";`);
console.log(`obj dataProperty1: ${getPropertyType(obj, "dataProperty1")}`);
console.log(`proto dataProperty1: ${getPropertyType(proto, "dataProperty1")}`);
console.log(`--- Before obj.dataProperty2 = "dataProperty2 updated";`);
console.log(`obj dataProperty2: ${getPropertyType(obj, "dataProperty2")}`);
console.log(`proto dataProperty2: ${getPropertyType(proto, "dataProperty2")}`);
obj.dataProperty2 = "dataProperty2 updated";
console.log(`--- After obj.dataProperty2 = "dataProperty2 updated";`);
console.log(`obj dataProperty2: ${getPropertyType(obj, "dataProperty2")}`);
console.log(`proto dataProperty2: ${getPropertyType(proto, "dataProperty2")}`);
console.log(`--- Before obj.readWriteAccessor = "readWriteAccessor updated";`);
console.log(`obj readWriteAccessor: ${getPropertyType(obj, "readWriteAccessor")}`);
console.log(`proto readWriteAccessor: ${getPropertyType(proto, "readWriteAccessor")}`);
obj.readWriteAccessor = "readWriteAccessor updated";
console.log(`--- After obj.readWriteAccessor = "readWriteAccessor updated";`);
console.log(`obj readWriteAccessor: ${getPropertyType(obj, "readWriteAccessor")}`);
console.log(`proto readWriteAccessor: ${getPropertyType(proto, "readWriteAccessor")}`);
console.log(`obj readOnlyAccessor: ${getPropertyType(obj, "readOnlyAccessor")}`);
console.log(`proto readOnlyAccessor: ${getPropertyType(proto, "readOnlyAccessor")}`);
console.log(`--- Before obj.readOnlyAccessor = "readOnlyAccessor updated";`);
try {
obj.readOnlyAccessor = "readOnlyAccessor updated"; // Would fail silently in loose mode, but we're using strict
console.log(`Worked!`);
} catch (e) {
console.error(`Assignment failed: ${e.message}`);
}
console.log(`--- After obj.readOnlyAccessor = "readOnlyAccessor updated";`);
console.log(`obj readOnlyAccessor: ${getPropertyType(obj, "readOnlyAccessor")}`);
console.log(`proto readOnlyAccessor: ${getPropertyType(proto, "readOnlyAccessor")}`);Run Code Online (Sandbox Code Playgroud)