代码之家  ›  专栏  ›  技术社区  ›  Samuel Hulla

callstack的行为和这个during.defineProperty方法

  •  0
  • Samuel Hulla  · 技术社区  · 6 年前

    预处理:

    如果你找到了答案,请跳到下面的实际问题 “背景故事”在这里没有必要。但我相信这会增加很多 问题的细节和进一步的背景

    最近我一直在用物体和 [[ Prototype ]] 链一点,

    this NaN 代码如下:

    var obj = {
      a: 2
    }
    
    Object.defineProperty(obj, 'b', {
      value: this.a + 2,
      enumerable: true
    });
    
    console.log(obj.b);


    我的 obj.b undefined + 2 ,于是又回来了

    现在,很明显,更改代码会显式引用 value: obj.a + 2 this.a 返回为 undefined .


    基本上,我的问题是我的调用堆栈引用了 Object.prototype.a Object.defineProperty 是否委派含蓄性 Object.prototype.defineProperty .

    a 作为 Object.prototype

    var obj = {
      a: 2
    }
    
    Object.prototype.a = obj.a;
    
    Object.defineProperty(obj, 'b', {
      value: this.a + 2,
      enumerable: true
    });
    
    console.log(obj.b);

    这将返回 4 到整个 对象.原型 绝对不是最好的编程实践,但为了便于说明,它将起到很好的作用)

    问题是:

    console.trace 在表达式上,我的调用堆栈纯粹由 (anonymous) global 关键字。

    很遗憾,您必须在自己的控制台中运行代码 console.trace() 不幸的是,jsfiddle不支持

    var obj = {
      a: 2
    }
    
    Object.prototype.a = obj.a;
    
    console.trace(Object.defineProperty(obj, 'b', {
      value: this.a + 2,
      enumerable: true
    }));
    

    enter image description here


    TL/DR公司:

    1. 为什么调用堆栈只返回 (匿名) 而且也不是 对象.原型
    2. 显式绑定的正确方法是什么 obj 在我们的 .defineProperty() 方法?

    先谢谢你。

    1 回复  |  直到 4 年前
        1
  •  1
  •   Avius    6 年前

    1) 为什么控制台.trace仅返回(匿名)

    function foo() {
      function bar() {
        console.trace();
      }
      bar();
    }
    
    foo();
    

    bar
    foo
    <anonymous>
    

    换句话说,你必须打电话控制台.trace() 从内部 酒吧 ),然后是调用函数的父函数的名称( 匿名的 函数-主执行线程,所有代码都从这里开始。

    每当您在devtools中执行某些代码时(我假设您正在使用这些代码),它总是以包装匿名函数的形式在这个全局执行上下文中执行。既然你打电话来了控制台.trace()立即从这个匿名函数,这是什么打印- .

    也,控制台.trace()接受参数。当你调用控制台.trace(),可以使用任意数量的参数,这些参数只需在堆栈跟踪之前打印到控制台。自Object.defineProperty属性()返回要为其定义新属性的对象,这是要传递给的对象控制台.trace().

    太长,读不下去了 - 控制台.trace()首先将其参数打印到控制台(即。 目标

    2) 这个,定义属性等等

    第三个论点Object.defineProperty属性是一个简单的物体, ! 它的属性在初始化过程中立即被解析,只有在那个时候它才被传递到defineProperty中。这意味着以下代码在功能上与您的代码相同:

    // First we initialize the third argument, separately from the call
    // to .defineProperty()
    
    var descriptor = {
      value: this.a + 2,
      enumerable: true
    };
    
    // at this point descriptor is already constructed. If you do
    // console.log(descriptor.value) here, you will get NaN or maybe
    // 4 or something else, depending on what you did before
    
    Object.defineProperty(obj, 'b', descriptor);
    // Here we simply invoke .defineProperty with descriptor as the third argument.  
    

    您还必须知道,当您在主执行上下文中运行代码时(例如,从devtools控制台调用代码),

    更有趣的是,这个.a(或window.a)在你完成之后变成了2对象.原型.a=2。这是因为窗口仍然是一个 对象 对象的原型

    obj.prototype = {a: 2};
    

    var proto = {}; // First create a prototype
    obj.prototype = proto; // Then assign it to the prototype property of your obj
    obj.prototype.a = 2; // Now we can alter props on the prototype
    

    看到区别了吗?这更有意义吗?当然,执行此操作后,代码将不再工作,因为this.a将再次变得未定义。

    不能 价值 可枚举的 ,如果对其实现set()&get()方法,则应该能够获得所需的行为。另外,我相信你可以使用代理来获得类似的行为。没有提供更多的细节,我建议您先阅读函数执行上下文,然后再阅读一些关于原型的内容,也许还有一些关于堆栈溢出的关于 . 在那之后,你可以试着研究提议的解决方案。