需要了解Javascript对象引用

时间:2014-11-15 00:20:56

标签: javascript

我正在查看John Resig网站上的这段代码。我不明白的是当忍者对象被设置为空对象时,yell方法仍然可供武士使用。

是因为因为忍者周围还有一个参考物,所以它不是垃圾收集的吗?

var ninja = {
  yell: function(n){
    return n > 0 ? yell(n-1) + "a" : "hiy";
  }
};


var samurai = { yell: ninja.yell };

ninja = {};

console.log(samurai.yell(2)); //hiy

http://ejohn.org/apps/learn/#14(原始来源,我稍微修改了一下以删除指定的函数表达式)。

4 个答案:

答案 0 :(得分:5)

在以下代码中:

var ninja = {
  yell: function(n){
    return n > 0 ? yell(n-1) + "a" : "hiy";
  }
};

ninja.yell 的值是对函数的引用。作业:

var samurai = { yell: ninja.yell };

samurai.yell 指定一个值,该值是对同一函数的引用(即 ninja.yell 引用的那个)。然后:

ninja = {};

ninja 指定一个值,这是一个新的空对象。它对分配给 samurai.yell 的值没有影响,它仍然引用该函数。

变量有一个值,值为Type。有一个名为Reference Type的特殊类型是" ...用于解释诸如delete,typeof和赋值运算符"等运算符的行为。因此,当对象位于assignment expression时,分配的值为Type Reference。

因此变量仍然有一个值,但它的值是一个参考。

答案 1 :(得分:1)

打破'ninja'的'yell'属性引用的匿名函数:

function yell(n) {
  return n > 0 ? yell(n-1) + "a" : "hiy";
}

var ninja = {
  yell: yell
};

现在,当你重新分配'ninja'时,更容易看到'yell'功能没有被'删除'。

当你这样做时:

var samurai = { yell: ninja.yell };

您将任何ninja.yell引用(function yell()}指定给'samurai.yell'。

答案 2 :(得分:0)

查看此原始未修改的来源非常重要:

 1. | var ninja = { 
 2. |   yell: function(n){ 
 3. |     return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
 4. |   } 
 5. | }; 
 6. | assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 
 7. |  
 8. | var samurai = { yell: ninja.yell }; 
 9. | var ninja = null; 
10. |  
11. | try { 
12. |   samurai.yell(4); 
13. | } catch(e){ 
14. |   assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
15. | }

您将ninja.yell更改为yell所做的更改是对脚本的无效修改。

  

我不明白的是,当忍者对象被设置为空对象时,yell方法仍可供武士使用。

了解如何在JavaScript中进行赋值非常重要。 JavaScript有很多方便的简写符号,当你对这门语言不熟悉时,它会让你更难理解。

var samurai = { yell: ninja.yell };

是一种简写的说法:

var samurai;
samurai = new Object();
samurai.yell = ninja.yell;

调用samurai.yell = ninja.yell后,ninja.yell功能的引用会添加到samurai

在JavaScript中,函数也是对象。它们通过引用传递。 samurai.yell = ninja.yell 未执行的操作会复制对ninja的任何类型的引用。

在示例的第9行, var ninja = null不会以任何方式修改ninja.yell处的功能。它也不会以任何方式修改以ninja存储的对象。它的作用是删除对ninja存储的对象的引用,并将其替换为值null。这意味着ninja引用的对象的任何其他副本仍将指向ninja引用的对象。

通过示例更容易看到:

var foo,
    bar;

foo = {
    fizz: 'buzz'
};
bar = foo;
foo = null;
console.log(bar.fizz); //buzz
  

是因为因为忍者周围还有一个参考,所以它不是垃圾收集的吗?

在执行示例脚本的第9行之后,不再有ninja处对象的任何引用。 ninja.yell处的函数的引用。这意味着ninja对象可以被垃圾收集,但ninja.yell对象(恰好是一个函数)不能。

答案 3 :(得分:0)

以JavaScript解释器的方式运行执行:

  1. 创建一个新的匿名空对象(标识为obj1)。
  2. 创建一个名为func1的新匿名函数return n > 0 ? ...
  3. 向此对象obj1添加一个名为yell的新属性,该对象是函数func1的别名。
  4. 将对此对象的引用分配给名为ninja的新根属性(变量可以被视为字段属性)。
  5. 此时,“堆”看起来像这样:

    func1 = n => return n > 0 ? yell(n-1) + "a" : "hiy"
    obj1  = { yell: func1 }
    ninja = obj1
    
    1. 创建一个新的匿名空对象(标识为obj2)。
    2. 向此对象obj2添加一个名为yell的新属性,该对象是函数func1的别名 - 不是 ninja.yell的别名 - 对“函数值”本身的引用被复制到obj2.yell而不是引用到函数的引用。
    3. obj2分配给samurai
    4. 创建一个新的匿名空对象(标识为obj3)。
    5. 将对象的引用分配给ninja
    6. 此时,“堆”看起来像这样:

      func1   = n => return n > 0 ? yell(n-1) + "a" : "hiy"
      obj1    = { yell: func1 } // this no-longer has any references and will be GC'd at some point
      obj2    = { yell: func1 }
      obj3    = {}
      samurai = obj2
      ninja   = obj3
      
      1. 致电samurai.yell,取消引用obj2,然后func1成功拨打电话。