Dan*_*nce 3 javascript inheritance prototype
我快速起草了一个小助手方法,使未定义的变量检查更容易一些.
Object.prototype.is = function() {
for(var i in arguments) {
if(this === arguments[i]) {
return true;
}
}
return false;
};
Run Code Online (Sandbox Code Playgroud)
设计使用如下:foo.is(undefined, false)检查foo是否未定义或错误.我使用的测试用例是:
var a = false;
a.is(false);
> false
Run Code Online (Sandbox Code Playgroud)
有点困惑,我多玩了一下.一些console.logging显示相等检查失败,因为被比较的两个对象不一样.
Boolean {is: function} === false
> false
Run Code Online (Sandbox Code Playgroud)
所以,从它的曾祖父a继承了这个is方法:Object.prototype但是false比较中没有.
我想我可以通过使用来强制继承new Boolean(false),这肯定会创建一个对象的新实例(希望避免在对象的原型被扩展之前创建的对象的引用可能发生的任何风险).结果:
Boolean {is: function} === Boolean {is: function}
> false
Run Code Online (Sandbox Code Playgroud)
为什么平等检查失败?
作为解决这里发生的事情的过程的一部分,我在使用单个布尔值作为参数调用函数之后检查了arguments数组,只发现它的长度为2,额外的参数是is函数在Object.prototype中声明.
a.is(false);
arguments -> [false, is: function]
Run Code Online (Sandbox Code Playgroud)
那是怎么结束的?
作为参考,我知道像这样的猴子修补是一个坏主意!这不是生产代码,我只是感兴趣.
这是另一个问题,this值被强制转换为一个对象 - 猴子补丁将添加'use strict'到你的函数的开头,这可以防止这种强制发生.但是,较旧的浏览器可能无法识别此指令.
如果函数不严格,那么基本上会发生以下情况:
var a = false;
Object.prototype.is.call(Object(a), undefined, false);
Run Code Online (Sandbox Code Playgroud)
当a转换为对象(通过调用Object(a))时,它将变为布尔对象,这与布尔值不同.例如,拿这个:
false === new Boolean(false); // false
Run Code Online (Sandbox Code Playgroud)
此外,对象在引用同一对象时仅相等:
new Boolean(false) === new Boolean(false); // false
var test = new Boolean(false);
test === test; // true, they are the same object
Run Code Online (Sandbox Code Playgroud)
发生的另一个问题是,当您is()调用函数null(并且它不严格)时,它将失败:
Object.prototype.is.call(null, null); // becomes window === null (false)
Run Code Online (Sandbox Code Playgroud)
使其成为严格函数的替代方法包括比较两者的对象值(尽管这会产生类似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;
};
Run Code Online (Sandbox Code Playgroud)
您在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
Run Code Online (Sandbox Code Playgroud)
默认情况下(当您"正常"定义它时),所有属性(无论是直接在对象上还是在原型链上)都是可枚举的,这意味着您可以在for-in循环和其他类似结构中看到它.但是,这(大多数情况下)并不是理想的行为 - 大多数原生原型函数都不是可枚举的.要解决此问题,您应该运行函数的索引,而不是属性:
for (var i = 0; i < arguments.length; ++i) // code here
Run Code Online (Sandbox Code Playgroud)