1 前言
首先个人不推荐修改原生对象。原因有两个:
- 没有必要。第三方类库和自定义类完全可以满足需求。
- 维护问题。
但是项目中总会遇到这样的情况,原生的js对象被修改,但是手法很拙劣。
那就开始吧。这里我们以Array为例。
2 不正确的姿势
2.1 Array.method
这样并不能为array 对象添加新的方法。
2.2 Array.prototype.method
添加了一个方法method,而且之后所有新建的Array对象都有了一个名叫method方法。
Array.prototype.method = function(){
console.log('I am an user defined method!');
}
var a = [];
a.method();
console中输出了 I am an user defined method!。看起来很完美啊。
但是当我们for in遍历这个数组的时候,发现method也出现在结果之中了。这显然不是我们希望的结果。
for(x in a){
console.log(x+':'+a[x])
}
console中输出了 :
method:function (){
console.log('I am an user defined method!');
}
看起来这种方法是有副作用的。以后我们使用for in的时候,必须手动过滤掉这个method。
比如利用typeof
for(x in a){
if(typeof a[x] === 'function') continue;
console.log(x+':'+a[x])
}
3 正确姿势
这是正确的方式,先上代码:
Object.defineProperty(Array.prototype,'method',{
writable:false,
enumerable:false,
configurable:true,
value:function(){
console.log('I am an user defined method!');
}
});
是否有效大家可以自己尝试,下面说明一下其中的参数。
- Array.prototype 表示属性会添加到Array的prototype,这样,所有新建的数组对象都会拥有这个属性。
- ‘method’ 属性名,可以使用变量。这样就可以动态的添加某些属性了。
- {} 一个对象,包含四个属性,当某个属性未提供时,默认是false或者undefined。
writable
enumerable 是否可被枚举,设为false,就不能被for in遍历到啦。
configurable
value 属性的值
writable 和 configurable 的规则比较复杂,并不像字面上那样简单。暂时不解释。
如果要一次定义多个属性
可以这样
Object.defineProperties(Array.prototype,
{
method1:{
writable:true,
enumerable:false,
configurable:true,
value:function(){
console.log('I am an user defined method 1!');
}
},
method2:{
writable:true,
enumerable:false,
configurable:true,
value:function(){
console.log('I am an user defined method 2!');
}
}
}
);
注意这种方式不方便传递动态的函数名了。
4 总结
JavaScript允许修改,扩展原生类的属性,并且在属性的特性,如可修改,可枚举,可配置上提供了一些选择。通过这些属性的组合可以设计出更加贴合实际需求的类。比如,我们可以设计一个Person类,当Person的性别被初始化之后,不允许再进行修改(个别情况还是允许的)。