为什么在这里需要确切的二传手?

时间:2019-05-12 09:58:20

标签: javascript

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>

我在那里不需要二传手,浏览器到底要我做什么?

1 个答案:

答案 0 :(得分:5)

  

无法将属性#<Docum>的clientName设置为仅具有吸气剂

通过对定义为访问器的属性进行this.childYes = ...,您正在尝试使用setter。要在实例上定义属性,请使用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;行的位置,而是因为这是对的。分配给对象属性时,发生的情况取决于该属性是否存在于对象或其原​​型上,如果存在,则取决于该属性是 data属性还是 accessor属性< / em>:

  1. 如果该属性(在对象或其任何原型上)根本不存在,则JavaScript引擎会将其创建为原始对象上的data属性,并为其赋值。
  2. 如果它作为数据属性存在(在对象或其任何原型上),则引擎将在原始对象上创建或更新它,并为其分配值。
  3. 如果它作为访问器属性存在,则
    1. 如果它有一个设置器,它将调用该设置器
    2. 否则,将引发错误

在原始代码中,您完成了上面的步骤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;
}