Nodejs中这道关于Object.prototype的题目,为什么每次 obj 会改变呢?

Nodejs中这道关于Object.prototype的题目,为什么每次 obj 会改变呢?

Object.prototype.hash = function(string) {
var obj = this;
string.split(".").forEach(function(el) {
console.log(obj); // 为什么每次 obj 会改变呢?

try {
  obj = obj[el];
}
catch(e) { 
  obj = undefined;
}

}); return obj; }

// 测试用例 var obj = { person: { name: ‘joe’, history: { hometown: ‘bratislava’, bio: { funFact: ‘I like fishing.’ } } } };

console.log(obj.hash(‘person.name’)); console.log(obj.hash(‘person.history.bio’)); console.log(obj.hash(‘person.history.homeStreet’)); console.log(obj.hash(‘person.animal.pet.needNoseAntEater’));

发现每一次循环,obj都递减了层次。


4 回复

要理解为什么在 obj.hash 方法中的 obj 会改变,我们需要深入分析代码。让我们一步一步地解析这个问题。

示例代码解析

Object.prototype.hash = function(string) {
  var obj = this;
  string.split(".").forEach(function(el) {
    console.log(obj); // 为什么每次 obj 会改变呢?

    try {
      obj = obj[el];
    } catch(e) { 
      obj = undefined;
    }
  });
  return obj;
}

// 测试用例
var obj = {
  person: {
    name: 'joe',
    history: {
      hometown: 'bratislava',
      bio: {
        funFact: 'I like fishing.'
      }
    }
  }
};

console.log(obj.hash('person.name')); // 输出 'joe'
console.log(obj.hash('person.history.bio')); // 输出 { funFact: 'I like fishing.' }
console.log(obj.hash('person.history.homeStreet')); // 输出 undefined
console.log(obj.hash('person.animal.pet.needNoseAntEater')); // 输出 undefined

解析

  1. 方法定义

    • Object.prototype.hash 是一个方法,它被添加到所有对象的原型链上。
    • 这个方法接收一个字符串参数 string,并根据这个字符串分割成路径片段。
  2. 字符串分割

    • string.split(".") 将输入的字符串按点号 . 分割成数组,例如 'person.history.bio' 会被分割成 ['person', 'history', 'bio']
  3. 遍历分割后的数组

    • 使用 forEach 遍历分割后的数组。
    • 每次迭代时,当前的 obj 会被更新为 obj[el],即 obj 的属性。
  4. 异常处理

    • 如果在访问 obj[el] 时抛出异常(例如属性不存在),则将 obj 设置为 undefined

为什么 obj 会改变

在每次迭代中,obj 被重新赋值为当前路径下的子对象。例如:

  • 第一次调用 hash('person.name') 时,obj 初始值为测试对象本身。
  • 第一次迭代时,el'person',所以 obj 变为 obj.person,即 { name: 'joe', history: { hometown: 'bratislava', bio: { funFact: 'I like fishing.' } } }
  • 第二次迭代时,el'name',所以 obj 变为 obj.person.name,即 'joe'

由于 obj 在每次迭代中都被重新赋值,因此它的值会随着路径的变化而变化。

输出结果解释

  • console.log(obj.hash('person.name')) 输出 'joe',因为 obj.person.name 的值是 'joe'
  • console.log(obj.hash('person.history.bio')) 输出 { funFact: 'I like fishing.' },因为 obj.person.history.bio 的值是 { funFact: 'I like fishing.' }
  • console.log(obj.hash('person.history.homeStreet')) 输出 undefined,因为 obj.person.history.homeStreet 不存在。
  • console.log(obj.hash('person.animal.pet.needNoseAntEater')) 输出 undefined,因为路径中的属性都不存在。

通过这种方式,你可以看到 obj 的值如何随路径变化而变化。


可能没理解到你的意图。不过obj改变难道不是因为这句:

 obj = obj[el];

楼主,我写了个库干这事:https://github.com/alsotang/ettr

在你的代码中,obj 的值在 string.split(".").forEach 循环中不断变化。每次迭代时,obj 都会被重新赋值为当前路径上的下一个对象属性。如果路径不存在,则 obj 被设置为 undefined

这是因为在每次迭代中,你都在修改 obj 的值:

obj = obj[el];

这里 obj 会被更新为其属性 el 的值。因此,在多次迭代之后,obj 可能不再指向原始对象 this(即传入 hash 方法的对象)。

为了更清楚地理解这个问题,我们可以添加一些日志来查看 obj 在每次迭代中的变化情况。

下面是带有详细日志输出的代码示例:

Object.prototype.hash = function (string) {
  let obj = this;
  string.split(".").forEach(function (el) {
    console.log(`Current obj:`, obj);
    try {
      obj = obj[el];
      console.log(`After accessing '${el}':`, obj);
    } catch (e) {
      obj = undefined;
      console.log(`Caught exception, setting obj to undefined`);
    }
  });
  return obj;
};

// 测试用例
var obj = {
  person: {
    name: 'joe',
    history: {
      hometown: 'bratislava',
      bio: {
        funFact: 'I like fishing.',
      },
    },
  },
};

console.log(obj.hash('person.name')); // 输出 'joe'
console.log(obj.hash('person.history.bio')); // 输出 'I like fishing.'
console.log(obj.hash('person.history.homeStreet')); // 输出 undefined
console.log(obj.hash('person.animal.pet.needNoseAntEater')); // 输出 undefined

通过这段代码,你可以看到每次迭代时 obj 的值是如何变化的。

回到顶部