一、原型
1.每个函数,都有一个内置属性,叫做prototype(原型)(prototype是一个对象)
2.如果一个对象是通过new产生的,那么这个对象将有缺省的属性,__ proto__,这个属性指向函数的原型
原型的用处:用来让所有的构造函数生成的对象可以共享属性和方法,构造函数产生的对象获得,prototype的属性和方法,在构造函数原型上的方法和属性都是共享的
function Dog(name, age){ //构造函数
this.name = name;
this.age = age;
}
Dog.prototype.eat = function(food){// 在构造函数的原型上面增加方法
console.log(food);
}
var dog1 = new Dog('doubao', 3); //实例
var dog2 = new Dog('wawa', 4);
//下面为共用一个方法
dog1.eat('apple');//运行结果为 apple
dog2.eat('rice'); //运行结果为 rice
console.log(dog1.eat === dog2.eat);//运行结果为true
//下面为共用一个属性
Dog.prototype.headNumber = '1';
console.log(dog1.headNumber);//运行结果为1
console.log(dog2.headNumber); //运行结果为1
原型的方法,既可以访问原型中的其他的方法和属性,也可以访问实例上自己的属性
// 原型的方法,既可以访问原型中的其他的方法和属性,也可以访问实例上自己的属性
Dog.prototype.eat2 = function(){
this.eat('meat'); //访问原型中其他的方法
console.log(this.headNumber); //访问原型中其他的属性
console.log(this.age);//访问实例中自己的属性
}
dog1.eat2(); //运行结果为 meat
1
3
原型的性质:
1.直接在实例上增加方法或者属性,是属于实例本身的,不会影响构造函数的原型
2.当运行需要实例的某种方法或者属性时,首先在实例本身上寻找方法或者属性,如果找不到去原型上找,如果还找不到,返回undefined
dog1.headNumber = '2' //直接在实例上增加与在原型上相同的属性,但属性内容同
console.log(dog1.headNumber);//运行结果为2 首先在实例本身上寻找方法或者属性
console.log(dog2.headNumber);//运行结果为1 在实例dog1增加的属性不会影响到构造函数的原型
二、原型链
原型链顾名思义是一条链式的结构,首先先来看一个简单的例子
用代码来对上述图片进行实现
//创建构造函数
function A1(){
this.m = 'mm';
}
//用Object创建一个对象obj,并给obj增加属性和方法
var obj = new Object;
obj.n = 'nn';
obj.f = function(){
console.log('123')
}
//用obj替换A1.prototype
A1.prototype = obj;
obj.constructor = A1;
//创建实例
var a1 = new A1();
console.log(a1.n);//运行结果为 nn
a1.f(); //运行结果为 hello
由此我们可见,我们可以用一个实例对象来替换一个构造函数的prototype,并且此实例对象原本的属性和方法,也能被构造函数所创造出的实例所用。
构造原型链的步骤
1.从Object开始,每一层底层的构造函数构造出实例,作为上一层构造函数的原型对象
2.构造好后,通过对象的 _proto__,可以一直追溯到null\Object,这个链表称为原型链
我们再来看一个三层继承的例子
用代码来对上述图片进行实现
//创建obj对象实例,并在obj上增加属性
var obj = new Object();
obj.objM = 'objMM';
//创建A1构造函数
function A1(){
this.g = 'gg'
}
//使obj成为A1.prototype
A1.prototype = obj;
obj.constructor = A1;
//通过构造函数A1创建对象实例a1,并在a1上增加属性
var a1 = new A1();
a1.a1M = 'a1MM';
//创建A2构造函数
function A2(){
this.h = 'hh'
}
//使a1成为A2.prototype
A2.prototype = a1;
a1.constructor = A2;
//通过构造函数A2创建对象实例a2,并在a2上增加属性
var a2 = new A2();
a2.a2M = 'a2MM';
//创建A3构造函数
function A3(){
this.i = 'ii'
}
//使a2成为A3.prototype
A3.prototype = a2;
a2.constructor = A3;
//通过构造函数A3创建对象实例a3
var a3 = new A3();
//通过实例对象a3来依次调用原型链各层的属性
console.log(a3.a2M);//运行结果为a2MM
console.log(a3.a1M);//运行结果为a1MM
console.log(a3.objM);//运行结果为objMM
原型链的性质:
1.所有挂在原型链对象上的属性和方法,能够被所有派生实例共享
2.如果访问一个示例的属性或者方法,先从对象本身找起,如果发现没有,会沿着原型链由近至远寻找