【问题标题】:Object.defineProperty in constructor, getter and setter method构造函数、getter 和 setter 方法中的 Object.defineProperty
【发布时间】:2016-10-19 21:43:06
【问题描述】:

define property in constructor 这里提出了完全相同的问题,但我觉得答案并不令人满意。 代码抄自《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 在行后超出范围: var One = new Person("Mark");稍后如何在代码对象的 One getter 中设法返回 xname 的值??

  3. 它是的值xname,因为如果我改变getter方法返回name,就像它应该工作一样,引擎报告错误 name is not defined。 (get: function() {return name;})

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

没有将 xname 分配给 .name 或者有但我没有看到?!

【问题讨论】:

  • “我已经将参数名修改为xname,因为使用同名的局部变量和对象属性更加混乱。”只有。你错过了二传手。
  • * 有 => 一半 (对不起)

标签: javascript


【解决方案1】:

getter 方法返回xname 而xname 在以下行之后超出范围:var One = new Person("Mark"); 稍后如何在代码对象的 One getter 中设法返回xname 的值??

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

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

我已将参数名称修改为 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"

如您所见,当我们调用c1 或c2 函数时,它使用arg 在创建该函数时收到的arg 参数,即使createClosure 已返回。 c1(和c2)每个都有对创建它们的上下文的引用。他们“关闭”了与创建它们的调用相关的arg。

更多阅读:

【讨论】:

  • 好的。谢谢。闭包可能会以我还不知道的方式起作用,这本书到目前为止还没有提到它们,但是我
  • 好的。谢谢。闭包可能以我还不知道的方式工作,这本书到目前为止没有提到它们,但我没有从书中得到代码 sn-p。他正在定义名为“name”的新 Person 对象的属性。为什么 setter 应该将 newName 分配给 .name 的 xname?如果您不使用 defineProperty,那么相同的代码会是什么?像这样的东西?函数人(姓名){ this.name = name; this.get = function() {return this.name;}; this.set = function(v) {this.name = v;}; }
  • @b'stard:如果这本书还没有介绍闭包,那么他们应该把上面的代码扔给你,这有点令人难以置信;你可能会考虑另一本书。 Re name vs. xname:在getter/setter代码中,Person的参数名称完全不相关;它对属性的名称没有任何影响。属性的名称由defineProperty 的第二个参数确定。当您使用 getter/setter 时,您将存储数据的位置(如果您这样做的话)与属性本身分离。我们存储它的 arg/变量的名称无关紧要。
  • 感谢您的耐心等待。作为一名 C 程序员,我从未考虑过函数返回后自动变量存在的可能性。这是正在发生的事情吗:局部变量不会自动丢弃,但垃圾收集器负责它们的生命周期。只要有对变量的引用,GC 就会让它保持活动状态。在我的示例中,对象 One 引用了“本地”变量 xname,因此在删除对象 One 之前不会释放它?
  • @b'stard:就是这样。从概念上讲,函数调用的局部变量(和参数)保存在一个对象中(我们称它为“环境对象”——它正确地是 LexicalEnvironment的 EnvironmentRecord > ExecutionContext 的调用);在该调用中创建的函数具有对该对象的引用。如果调用返回后函数继续存在,则环境对象也继续存在,因此它包含的局部变量继续存在。这些对象的生命周期由 GC 处理。
猜你喜欢
  • 1970-01-01
  • 2013-07-30
  • 1970-01-01
  • 2017-03-05
  • 2011-07-10
  • 2013-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多