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/

10-12 15:19