构造函数、getter和setter方法中的Object.defineProperty

Object.defineProperty in constructor, getter and setter method

本文关键字:Object defineProperty 方法 setter getter 构造函数      更新时间:2023-09-26

这里问的是完全相同的问题在构造函数中定义属性,但我不觉得答案是令人满意的。代码是从"The Principles of Object Oriented JavaScript"一书中复制而来的,并做了一些修改,使问题更清楚。

function Person(xname) {
    Object.defineProperty(this, "name", {
        get: function() {
            return xname;
        },
        set: function(newName) {
            name = newName;
        },
        configurable: true,
        enumerable: true
    });
    this.sayName = function() {
        console.log(this.name);
    };
}
var One = new Person("Mark");
One.sayName();
console.log(One.name);
//output:
//Mark
//Mark

我已经将参数name修改为xname,因为使用相同名称的局部变量和对象属性会更加混乱。

我怀疑这段代码是否按预期工作,但它甚至让我感到困惑,它正在做一些事情。

  1. 我知道它是在构造函数中使用Object.defineProperty来为新创建的实例创建一个名为"name"的属性。

  2. getter方法返回xname,然而xname在行之后超出了作用域:如何在代码对象的一个getter管理返回xname的值??

  3. 并且xname的值,因为如果我更改getter方法返回name,就像它应该工作一样,引擎报告错误name未定义。(get: function(){返回name;})

  4. 更不用说setter方法根本不起作用了。如果我编码One.name = "Mickey", One.name仍然设置为"Mark"

没有xname赋值给。name,或者有,但我没有看到?!

getter方法返回xname,然而xname在行之后超出范围:var One = new Person("Mark");如何在代码对象的一个getter管理返回xname的值??

因为仍然在的作用域中。是的,Person函数已经返回,但是因为有些函数关闭了调用Person的上下文,所以在该上下文中定义的参数和变量仍然可以被这些函数访问。

当你调用一个函数时,在规范术语中创建一个对象,该对象包含函数参数的"绑定"(把它们想象成属性),调用中的局部变量等。在调用该函数期间创建的任何函数都会维护对该对象的引用,因此即使在函数返回之后,该对象仍然存在。这是JavaScript闭包的基础。这就是为什么你可以继续使用xname,即使Person已经从调用中返回,在该实例上创建getter和setter。

我已将参数名称修改为xname,因为使用相同名称的局部变量和对象属性会更加混乱。

你只在getter中做过;你需要在getter 和setter 中都这样做才能正常工作:

function Person(xname) {
    Object.defineProperty(this, "name", {
        get: function() {
            return xname;
        },
        set: function(newName) {
            xname = newName;        // *** Here too
        },
        configurable: true,
        enumerable: true
    });
    this.sayName = function() {
        console.log(this.name);
    };
}

Object.defineProperty的东西(事实上,甚至new)都有点无关紧要。您看到的最基本的东西是闭包是如何工作的,所以让我们看一个更简单的例子:

function createClosure(arg) {
  return function() {
    console.log(arg);
  };
}
var c1 = createClosure("one");
var c2 = createClosure("two");
c1(); // "one"
c2(); // "two"
c1(); // still "one"
c2(); // still "two"

可以看到,当我们调用c1c2函数时,它使用createClosure在创建该函数时接收到的arg参数,即使createClosure已经返回。c1(和c2)都有一个对创建它们的上下文的引用。它们"关闭"了与创建它们的调用相关的arg

更多阅读:

  • 闭包是如何工作的?
  • 闭包并不复杂在我贫乏的小博客(选择标题是因为它们看起来复杂,但实际上很简单)