什么时候需要重写prototype
对于一个类,它天生自带一个属性:prototype
。但是有时候,我们会重写类的原型。
比如,在继承的时候,我们想通过原型让子类B继承父类A的原型上的属性和方法(公有继承公有)。
function A() {
this.x = 10;
}
A.prototype.say = function () {
};
function B() {
this.y = 10;
}
B.prototype = A.prototype;
var b = new B;
console.log(b.say); //=>输出say函数体
通过B.prototype = A.prototype;
让子类B的原型重新指向一个地址。
重写原型需要注意的点(恢复constructor和恢复原有方法)
- 对于内置类(如Object)的原型,浏览器为了保护里面的内置方法,是不允许重新创建一个堆内存覆盖原有的。
Object.prototype = {
a:function () {
}
};
console.log(Object.prototype); //输出原来的Object.prototype
注:在IE浏览器中,浏览器禁止使用__proto__这个属性(本身存在,只不过被保护起来了,不允许使用)
- 我们手动创建一个新的内存给
Fn.prototype
,此时,这个手动创建的prototype是不会默认自带constructor
属性的(使用instanceof
运算符就无法找到实例对象所属的类了)。 - 重写原型,会把之前浏览器默认创建的prototype覆盖,所以之前在原型上的方法和属性都不存在了,需要恢复。
恢复类默认原型上的属性和方法:
注意两点:function Fn() { } Fn.prototype.b = function () { console.log(1); } var pro = Fn.prototype; Fn.prototype = { constructor: Fn, // 无法在recover中恢复,需要手动写 b: function () { // 重复方法b,在执行recover的时候会被原有的方法b覆盖 console.log(2); }, c: function () { }, recover: function () { //recover是在不知道原有类的原型上是否存在方法的时候,编写的一个还原原有公有属性和方法的函数 for(var key in pro){ this[key] = pro[key]; } } } Fn.prototype.recover(); //执行后恢复 var f = new Fn; f.b(); //=>1
1)for in
循环能遍历对象中所有的属性和方法(私有+公有),但对于浏览器内置的一些属性(如constructor
、__proto__
等),无法用for in
遍历获取,这是浏览器对内置属性和方法的一个保护。
2)在recover方法中,为了防止还原时原有的方法将自定义原型方法的覆盖,最好修改自定义方法名。优化recover方法
:recover: function () { //优化后的recover for(var key in pro){ if(key in this){ this["my_"+key] = this[key]; this[key] = null; } this[key] = pro[key]; } } var f = new Fn; f.b(); //=>1 f.my_b(); //=>2