3

我很快起草了一个小辅助方法,使未定义的变量检查更容易一些。

Object.prototype.is = function() {
   for(var i in arguments) {
       if(this === arguments[i]) {
           return true;
       }
   }
   return false;
};

设计如下:foo.is(undefined, false)检查 foo 是否未定义或为假。我使用的测试用例是:

var a = false;
a.is(false);
> false

有点困惑,我又玩了一会儿。一些 console.logging 显示相等检查失败,因为被比较的两个对象不相同。

Boolean {is: function} === false
> false

所以,从它的曾祖父a那里继承了方法: Object.prototype 但在比较中没有。isfalse

我想我可以通过使用它来强制继承,new Boolean(false)这肯定会创建一个对象的新实例(希望能规避在扩展 Object 的原型之前创建的对象的引用可能发生的任何风险)。结果:

Boolean {is: function} === Boolean {is: function}
> false

为什么平等检查失败?

作为解决这里发生的事情的过程的一部分,我在使用单个布尔值作为参数调用函数后检查了参数数组,结果发现它的长度为 2,额外的参数is是在 Object.prototype 中声明。

a.is(false);
arguments -> [false, is: function]

那是怎么结束的?

作为参考,我知道像这样修补猴子是个坏主意!这不是生产代码,我只是感兴趣。

4

1 回答 1

5

有什么问题?

这是值被强制转换为对象的另一个问题this- 猴子补丁将添加'use strict'到函数的开头,从而防止发生这种强制。但是,较旧的浏览器可能无法识别此指令。

如果函数不严格,基本上会发生以下情况:

var a = false;
Object.prototype.is.call(Object(a), undefined, false);

a转换为对象(通过调用Object(a))时,它被转换为布尔对象,这与布尔值不同。例如,采取这个:

false === new Boolean(false); // false

此外,对象仅在引用同一个对象时才相等:

new Boolean(false) === new Boolean(false); // false
var test = new Boolean(false);
test === test; // true, they are the same object

发生的另一个问题是,当您的is()函数被调用null(并且它不严格)时,它将失败:

Object.prototype.is.call(null, null); // becomes window === null (false)

我能做些什么呢?

使其成为严格函数的替代方法包括比较两者的对象值(尽管这会使某些事情变得像new Boolean(false).is(false)new Boolean(false).is(new Boolean(false))成为真的,这可能是无意的。

您可以采取的另一种选择是将其设置为非原型函数,即改为使其类似于Object.is(尽管请注意 ES6 可能会定义一个Object.is与您的行为不同的本机函数):

Object.oneIsEqual = function (arg, compare)
{   for(var i = 0; i < compare.length; ++i) if (arg === compare[i]) return true;
    return false;
};

请注意您的编辑:

您在循环中获取原始函数的原因for-in是因为您已经在原型上定义了它,并且它是可枚举的(稍后会详细介绍)。

arguments对象有一个原型Object.prototype,它允许is函数可以在 上访问arguments

Object.prototype.is = function() {
   for(var i in arguments) {
       if(this === arguments[i]) {
           return true;
       }
   }
   return false;
};
(function () { return arguments.is; })(); // is the same function as to Object.prototype.is

默认情况下(当您“通常”定义它时),所有属性(无论是直接在对象上还是在原型链上)都是可枚举的,这意味着您可以在for-in循环和其他类似构造中看到它。然而,这(大多数时候)并不是我们想要的行为——大多数原生原型函数是不可枚举的。要解决此问题,您应该遍历函数的索引,而不是属性:

for (var i = 0; i < arguments.length; ++i) // code here
于 2013-11-07T04:23:32.153 回答