我一直在阅读一些javascript库的代码。我注意到AngularJS和Backbone.js都保留了对数组函数的本地引用。例如:
var push = [].push // or array.push
当数组是语言的结构并且应该可以全局访问时,这样做有什么意义呢?
答案 0 :(得分:11)
因为Array原型的函数可以应用于非数组。
例如,push
将项目放入类似数组的对象中:
var o = { length: 0 };
[].push.call(o, 'hi');
o; //Object {0: "hi", length: 1}
另一种常见做法是slice
将arguments
对象转换为本机数组:
(function() {
return [].slice.call(arguments); //[1, 2]
}(1, 2));
正如您所看到的,保存对这些函数的引用可以减少查找开销,使代码更小并且更加简洁。
在我看来,这主要是为了方便和可读性,因为重复写[].arrayMethod
看起来相当笨拙。性能和缩小提升是额外的。
通过Angular的来源,我发现了以下情况:
push
用于JQLite prototype。请注意,jQuery对象具有类似于数组的结构,与此答案中的第一个示例类似;
slice
用于sliceArgs
,concat
和bind
个功能。 Backbone还slice
个参数对象(Events#trigger和Underscore methods proxying),它还在Collection#slice使用slice
。
答案 1 :(得分:3)
我认为图书馆开发人员特别热衷于让他们的图书馆能够适应页面上可能发生的随机事情。如果您在早期获得对正确的Array.prototype.push的引用并使用闭包来使其远离您作为库编写者不知道的其他代码,那么它会降低机会(并使其更容易如果页面上的其他代码决定劫持这种内置方法(Javascript非常宽松的话),则会发生意外情况。
考虑:
function Library(){
var push=[].push;
var data=[];
this.save1=function(x){push.call(data, x);}
this.save2=function(x){data.push(x);}
this.get=function(){console.log(data);}
}
var o=new Library();
//Random on-page code
Array.prototype.push=function(x){console.info("doSomethingCrazy!");}
//Lets use the library functionality!
o.save1(1);
o.save2(2);
答案 2 :(得分:0)
Douglas Crockford在其讲座The Metamorphosis of Ajax中指出的一个原因是,JavaScript库的开发人员可以有条件地添加实用程序方法,例如string.split之类的东西,这样它只会添加到对象的原型中如果它尚未由浏览器提供的标准库定义。