gpt4 book ai didi

javascript - 为什么这里需要 setter?

转载 作者:行者123 更新时间:2023-11-30 08:19:31 26 4
gpt4 key购买 nike

HTML 片段

 <div id="container">

<span class="no"></span>
<span class="yes"></span>
<span class="no"></span>
<span class="no"></span>

</div>

所以,一个 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);

但是如果我添加一个空的 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>

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

最佳答案

Cannot set property clientName of #<Docum> which has only a getter

通过做 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>


在您提出的评论中:

So, correct me if I'm wrong: After object.childYes is called, the program looks for own .childYes property of object first; fails; goes to the prototype; finds getter; starts to execute the getter and when the line this.childYes = span; appears the program looks for it "here" e.g. in prototype and fails, right?

这不是因为 this.childYes = span; 在哪里线是,但是是的,除此之外它是正确的。当您分配给一个对象属性时,会发生什么取决于该属性是否存在于对象或其原​​型上,如果存在,则该属性是数据属性还是访问器属性:

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

在您的原始代码中,您在上面的步骤 3.2 处结束,因为该属性作为原型(prototype)上的访问器属性存在。

下面是这些不同场景的示例:

"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 - 为什么这里需要 setter?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56098086/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com