Javascript 对象文字动态键

Javascript 对象文字动态键,javascript,node.js,Javascript,Node.js,我在中学习了节点函数编程教程,但当我尝试实现第12课的代码时,如下所示 function Spy(target, method) { var store={}; var self=this; var copy=target[method]; store[target[method]]=0; console.log(store); console.log(store[target[method]]); target[method]=function(){

我在中学习了节点函数编程教程,但当我尝试实现第12课的代码时,如下所示

function Spy(target, method) {
  var store={};
  var self=this;
  var copy=target[method];
  store[target[method]]=0;
  console.log(store);
  console.log(store[target[method]]);
    target[method]=function(){
        store[target[method]]+=1;
      return copy.apply(this,arguments);
    };
  
  return {count:store[target[method]]}; 
}

var spy = Spy(console, 'error');

console.error('calling console.error');
console.error('calling console.error');
console.error('calling console.error');

console.log(spy.count);

我在Spy中得到了
console.log(store)
,返回一个包含函数的对象。另外,最终返回
返回{count:store[target[method]]}从Spy返回未定义。有人能解释一下这两个原因吗?谢谢

因为设置
后存储[target[method]]=0
您正在将
target[method]
设置为等于一个函数,这会弄乱
store[target[method]]
的值,使其未定义。看起来您将要在
返回上使用
复制
值:

return {count:store[copy]}; 
虽然在这种情况下,
计数仍然是
0
,但这并没有帮助。这是因为您直接在
Spy
中返回对象
{prop:value,…}
,因此无法在
Spy
函数中真正修改它。尽管要绕过将对象定义为构造函数中的变量(
var returnObj={count:store[copy]};
),请返回该变量:
return returnObj
。现在您可以更新
returnObj.count
内部
[target[method]]

这是因为JavaScript中的对象是通过引用传递的

功能间谍(目标、方法){
var-store={};
var self=这个;
var copy=目标[方法];
存储[目标[方法]]=0;
var returnObj={count:store[copy]};
目标[方法]=函数(){
returnObj.count+=1;
返回copy.apply(这个,参数);
};
返回OBJ;
}
var spy=spy(控制台“错误”);
console.error('调用console.error');
console.error('调用console.error');
console.error('调用console.error');

console.log(spy.count)我想用我在您的代码中添加的额外日志来解释这些内容

function Spy(target, method) {
  var store={};
  var self=this;
  var copy=target[method];  // #0.1
  store[target[method]]=0; //  #0.2
  console.log('Before :: store', store); // #1
  console.log('Before :: target[method]', target[method]); // #2

  target[method]=function(){
      store[target[method]]+=1;
      return copy.apply(this,arguments);
  }; // #3

  console.log('After :: store', store);  // #4
  console.log('After :: target[method]', target[method]);  // #5
  return {count:store[target[method]]}; // #6
}

var spy = Spy(console, 'error');
console.log(spy.count);
target[method]
是一个类似于
function(){[native code]}
(用js-lib编写的代码替换native代码)的函数

0.2
中,您将此函数(以字符串形式)作为
store
对象的键,并将其值分配给
0
。 因此,您的存储对象看起来像

`Before :: store { 'function () { [native code] }': 0 }`
at
#1
目标[方法]
是位于
#2
的本机函数

现在在
#3
您正在为
目标[方法]
分配一个新函数,因此现在
目标[方法]
将引用您的新函数

因此,在
#4
中,您的存储对象保持不变。(因为键是函数的字符串化值。)这是

`After :: store { 'function () { [native code] }': 0 }`
但是,由于您在
#3
中进行了赋值,因此您的
目标[方法]
值已更改为新函数,即

After :: target[method] function (){
      store[target[method]]+=1;
      return copy.apply(this,arguments);
  }

现在在
#6
您正试图从存储对象中获取一个密钥,而该存储对象在
存储
对象中不存在,因此它
返回未定义的
并将计数值存储到
未定义的

非常感谢,现在这完全有意义:)本机代码来自何处,它看起来不像是Spy的调用者传入的东西?本机代码来自javascript引擎。您的代码运行在实现ECMA规范的Js引擎之上。在这个实现中,它们是一个名为
控制台
的对象,它具有
错误
功能。此错误函数也有一些实现,在我们的日志中,本机代码中的
指的是
控制台.error()
的实现。非常感谢您的解释和解决方案:}只想添加一个后续,在我读过的是这样的真理,在JS中传递对象应该比C++中的指针传递更像是通过C++中的引用,因为指针可以被重写?@ Sehanh,我仍然认为它是通过引用的,因为这是它的功能如何工作,而只是稍微不同地实现。它过去了。基本上,它是按引用的值传递的,所以它是按值传递实现的,但功能的作用就好像它是按引用传递一样。非常感谢您的投入,非常感谢您的帮助:)