Js原型链

  
 在JS中,实现继承主要是依靠原型链来实现的。
  1.原型链和原型继承的基本概念
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例都包含一个指向原型对象的内部指针。如果将原型对象作为一个实例,那么这个原型对象中就包含一个指向另一个原型对象的指针,一个一个连接起来,就成了原型链。

function A(x){
this.x = x;
}
A.prototype.x = 0;
function B(x){
this.x = x;
}
B.prototype = new A(1);
console.log(B.prototype.x); //1
// B.prototype是A的实例,也就是B继承于A,
function C(x){
this.x = x;
}
C.prototype = new B(2);
console.log(C.prototype.x); //2
//C.prototype是B的实例,C继承于B
var d = new C(3);
console.log(d.x); //3
//实例化C的构造函数,在C的内部this.x=3,所以d.x=3

  2.原型和实例的关系
在js中,一切都是对象,Function和Object都是函数的实例;构造函数的父原型指向于Function原型,Function.prototype的父原型指向于Object的原型,Object的父原型也指向于Function原型,Object.prototype是所有原型的顶层;

Function.prototype.a = function(){
console.log('我是父原型Function');
}
Object.prototype.a = function(){
console.log('我是父原型Object');
}
function AA(){
this.a = 'a';
}
AA.prototype={
BB:function(){
console.log('b');
}
}
//Function和Object都是函数的实例
console.log(AA instanceof Function); //true
console.log(AA instanceof Object); //true

//AA.prototype是一个对象,它是Object的实例,但不是Function的实例
console.log(AA.prototype instanceof Function); //false
console.log(AA.prototype instanceof Object); //true

//Function是Object的实例,同时Object也是Function的实例
console.log(Function instanceof Object); //true
console.log(Object instanceof Function); //true

//Function.prototype是Object的实例,但是Object.prototype不是Function的实例,说明Object.prototype是所有父原型的顶层
console.log(Function.prototype instanceof Object); //true
console.log(Object.prototype instanceof Function); //false

  3.谨慎地定义方法
子类有时候需要覆盖超类中的某个方法,或者需要添加超类中不存在的方法。
给原型添加方法的代码一定要放在替换原型的语句之后,先继承。

function A(x){
this.x = x;
}
A.prototype.x = 0;
A.prototype.say = function(){
console.log('我是A');
}
function B(x){
this.x = x;
}
B.prototype = new A(1);
B.prototype.bSay = function(){
console.log('我是B自己的方法');
}
B.prototype.say = function(){
console.log('我是B重写A中的say方法');
}
console.log(B.prototype.x); //1
var d = new B(2);
console.log(d.x); //2
d.say(); //我是B重写A中的say方法

//B重写不改变A中原来的内容
function C(x){
this.x = x;
}
C.prototype = new A(2);
var f = new C(3);
f.say(); //我是A

注意:在通过原型链实现继承时,不能使用对象字面量创建原型方法。因为这样会重写原型链。以下相当于把A的实例赋值给B的原型,然后又将B的原型替换成一个对象字面量。

function A(x){
this.x = x;
}
A.prototype.x = 0;
A.prototype.say = function(){
console.log('我是A');
}
function B(x){
this.x = x;
}
B.prototype = new A(1);
B.prototype = {
bSay : function(){
console.log('我是B的方法');
},
y : 100
};
var d = new B(2);
console.log(d.y); //100
d.bSay(); //我是B的方法
d.say(); //is not a function

  4.原型链的优缺点

function A(){
this.colors = ['red','yellow'];
}
function B(){
}
B.prototype = new A();
var b = new B();
b.x = 2;
console.log(b.x); //2
console.log(B.prototype.x); //1
b.colors.push('black');
console.log(b.colors); //["red", "yellow", "black"]
var b2 = new B();
console.log(b2.colors); //["red", "yellow", "black"]

优点:能够允许多个对象实例共享原型对象的成员及方法。
缺点:1.包含引用类型值的原型属性会被所有实例共享,子类属性(引用类型值)改变,超类也会改变。2.在创建子类型的实例时,不能向超类的构造函数中传递参数。实际上,应该说是没有办法在不影响所有对象实例的情况下,给超类的构造函数传递参数。
所以在实践中,很少会会单独使用原型链。

 

文章目录
|