HTML片段
<div id="container">
<span class="no"></span>
<span class="yes"></span>
<span class="no"></span>
<span class="no"></span>
</div>
因此,一个吸气剂,它返回一个元素
.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);
但是,如果我添加一个空的二传手,它可以正常工作:
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>
我在那里不需要二传手,浏览器到底要我做什么?
最佳答案
无法将属性clientName设置为仅具有getter的#<Docum>
通过在定义为访问器的属性上执行this.childYes = ...
,您正在尝试使用设置器。要在实例上定义属性,请使用Object.defineProperty
:
get childYes(){
let span = this.elem.querySelector(".yes");
Object.defineProperty(this, "childYes", {
value: span
});
return span;
}
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 property
<div id="container">
<span class="no"></span>
<span class="yes"></span>
<span class="no"></span>
<span class="no"></span>
</div>
在评论中,您询问:
因此,如果我错了,请纠正我:在调用object.childYes之后,程序首先查找对象的自己的
.childYes
属性;失败去原型;找到吸气剂开始执行吸气剂,当行this.childYes = span;
出现时,程序在“此处”寻找它,例如在原型上失败了吧?这不是因为
this.childYes = span;
行在哪里,而是因为除此之外,这是正确的。分配给对象属性时,发生的情况取决于该属性是否存在于对象或其原型上,如果存在,则取决于该属性是数据属性还是访问器属性:如果该属性根本不存在(在对象或其任何原型上),则JavaScript引擎会将其创建为原始对象上的data属性,并为其赋值。
如果它作为数据属性存在(在对象或其任何原型上),则引擎将在原始对象上创建或更新它,并为其分配值。
如果它作为访问器属性存在,则
如果有设置器,则调用设置器
如果不是,则抛出错误
在原始代码中,您结束了上面的步骤3.2,因为该属性在原型上作为访问器属性存在。
这是这些各种情况的示例:
"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")}`);
.as-console-wrapper {
max-height: 100% !important;
}
关于javascript - 为什么在这里需要确切的二传手?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56098086/