为什么向对象字面量的原型添加属性会改变它的“类型”?

8

我有一个简单的isPlainObject方法,用于测试JavaScript对象字面量:

var isPlainObject = function (obj) {
  return typeof obj === "object" && {}.toString.call(obj) === "[object Object]";
};

现在我有一个普通对象:
var obj = {'one': 1, 'two': 2, 'three': 3};

当我通过isPlainObject(obj)函数运行它时,它按预期工作并返回true。我的问题出现在向对象的原型添加属性时:
obj.constructor.prototype.four = 4;

现在当我在obj上运行isPlainObject(obj)时,它返回false。在两种情况下,typeof obj都返回object。在我向原型中添加属性之后,在第二个实例中toString返回[object Number]

到底发生了什么改变obj?发生了什么事情?

编辑: 只有在QUnit函数调用的范围内测试时,才会出现这种情况。

test("each", function() {

    _.each([1, 2, 3], function(i,v) {
      equal(v, i + 1, 'each iterator provided index and value from array');
    });

    var obj = {'one': 1, 'two': 2, 'three': 3};
    console.log(_.isPlainObject(obj)); // => true
    obj.constructor.prototype.four = 4;
    console.log(_.isPlainObject(obj)); // => false

});

编辑: 在isPlainObject中,当记录arguments类数组对象时,我得到了以下console.log

Logging out the <code>arguments</code> object

从日志来看,似乎数组现在有两个参数。但长度仍然是1


9
你正在使用什么(奇怪的)浏览器?对我来说它显示为“true”...? - Matt
4
我也是这样认为的。请问 typeof obj{}.toString.call(obj)` 对你来说返回什么? - Barmar
2
这个问题似乎显示出缺乏研究的努力。你的函数有几个部分;你是否调查过,看看哪一部分的行为与你的期望不同?(现在typeof obj是什么?现在{}.toString.call(obj)返回什么?) - ruakh
3
你不应该修改Object.prototype!(它是obj.constructor.prototype的原型)。然而我不确定这会如何影响你的函数。 - Bergi
3
你需要在每次循环中检查object.hasOwnProperty(prop)(例如types.hasOwnProperty(d)或者更好的方式是,永远不要修改Object.prototype!(真的!这就是为什么你不应该这样做!)虽然这可能是另一个“修改了Object.prototype,现在for..in不起作用”的问题的重复,但我建议关闭此问题。 - apsillers
显示剩余14条评论
1个回答

1
通过调用
({}).constructor.prototype

您正在访问所有对象的原型。因此,您实际上是在向每个本地对象添加一个“four”属性。
如果您想要扩展您的对象实例,最好需要一个新的构造函数,例如:
var Count = function() {
  this.one = 1;
  this.two = 2;
  this.three = 3;
}

var obj = new Count();
obj.four = 4;

或者扩展构造函数:

Count.prototype.four = 4;

无论如何...不确定这是否会破坏QUnit,但正如另一个帖子所建议的那样,hasOwnProperty应该可以解决问题。这里有一个类似的问题


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接