protype是个很有趣的属性,它是“类”所持有的属性。在javascript里原生提供的一些内置类,其本质也是“类”,内置类提供的方法我们也可以通过prototype来覆盖掉,这是件很有趣的事情。例如:
=========================================
var str = str2 = "ab,cd,ef,g";
var arr = str.split(",");
String.prototype.split = function(a){
return "hello,you input: " + a;
}
String.prototype.length = 200;
var arr2 = str2.split(",");
alert(str.length);
alert(arr);
alert(arr2);
Array.prototype.toString = function(){
return "12345";
}
alert(arr);
=========================================
猜猜看,会依次弹出什么?“10”,“ab,cd,ef,g”,“hello,you input: ,”,“12345”。呵呵,看来属性没办法覆盖,第一个没弹出“200”,但方法可以覆盖,不论是String类的split方法,还是Array类的toString方法,都被我们覆盖掉了。
当然,覆盖内置类提供的方法这种操作绝大部分时候都是不好的,通常情况下,我们更多的是为内置类提供更多的方法,让程序更好用,例如:
==========================================
var arr = ["a","b","c"];
var str = arr.join("-");
alert(str);
Array.prototype.join2 = function(a){
return this.join("^^^"+a+"^^^");
}
str = arr.join2("-");
alert(str);
==========================================
我们给内置类添加一个join2方法,让它在join数组的时候,能做更多我们自定义的事。因为修改的是内置类的原型,所以js中所有的原生数据都直接获得了新的方法,这是种很方便的功能。但这样的方法其实并不推荐,它会对原生内置类的原型造成“污染”,可能会出现奇怪的问题,特别是多人合作的时候,或者引入第三方js库的时候,出现一些奇怪的bug,查都不好查。我们更推荐的方法是定义一个新的类,然后把所有需要扩展的功能放到这个新的类里去,通过这个新的类来完成功能,而不是直接修改原型。如:
===========================================
var arr = ["a","b","c"];
var str = arr.join("-");
alert(str);
arrayManager = {
join : function(oarr,ostr){
return oarr.join("^^^"+ostr+"^^^");
}
}
str = arrayManager.join(arr,"-");
alert(str);
===========================================
prototype是什么意思呢?它表示“原型”,简单地说,js中的类是分两级来实现的,一级是“原型级”,它比较底层,另一级是“实例级”,实例级的优先级比原型级高,如果new一个类,调用方法的时候,先优先在实例级去查找有无这个方法,如果没有,才会去原型中找。实例级在分配内存时会为每个实例分配一个,而原型级只会在内存中分配一个,通过传址的形式传给每个类的实例。所以为了节约内存,我们更推荐写类的时候将方法通过prototype的方式写出来,而不要写在function里,例如:
=========================================
//不推荐的写法
function Dog(){
this.name = "WangCai";
this.call = function(){
alert("wang wang");
}
}
//推荐的写法
function Dog(){
this.name = "WangCai";
}
Dog.prototype = {
call : function(){
alert("wang wang");
}
}
=========================================
正因为prototype是通过传址的方式供各实例调用的,所以如果对prototype进行了修改,无需重新再new一遍,实例的方法就已经更改了:
=========================================
function Dog(name){
this.name = name;
}
Dog.prototype.call = function(){
alert("I'm "+this.name);
}
var myDog = new Dog("WangCai");
myDog.call();
Dog.prototype.call = function(){
alert("wang wang wang wang wang");
}
myDog.call();
function Cat(name){
this.name = name;
this.call = function(){
alert("I'm "+this.name);
}
}
var myCat = new Cat("Mimi");
myCat.call();
Cat.prototype.call = function(){
alert("miao miao miao miao miao");
}
myCat.call();
=========================================
myDog第一次call的时候,弹的是I'm WangCai,第二次就是wang wang wang wang wang了 ;myCat两次都弹的是I'm Mimi。
正是因为prototype的这种特性,所以open api的系统里,因为会支持第三方开发,为了防止第三方恶意覆盖掉javascript内置类的方法,都会封装一套接口给第三方使用,以阻止它们访问原生内置类的原型。