JavaScript高级程序设计(反刍) 5

第六章(下):

继承:
许多OO语言都支持两种继承方式:接口继承实现继承。接口继承只继承方法签名,实现继承则继承实际的方法。
接口继承就是仅继承一个方法名,直接调用,但是方法并不归属于继承的函数
实现继承则是继承了实际的方法,也就是将继承来的方法直接copy到继承函数身上

1.原型链继承:
原型链的基本思想就是通过原型的方式实现一种特殊的继承的方法,核心的写法就是让一个函数的原型去取得另一个函数的实例

function Suptype(name){
    this.name = name;
    this.sayName = function(){
		console.log(this.name);
	}
}
function Subtype(name,age){
    this.name =name;
    this.age = age;
    this.sayAge = function(){
		console.log(this.age);
	}
}
subtype.prototype = new Suptype();
var person1 = new Subtype("abc", 12);
person1.name;                                //abc
person1.age;                                 //12

所有原型都默认继承了Object,所以所有函数的默认原型都是Object的实例,因此所有的默认原型内部都存在一个prototype指针指向Object.prototype
原型继承
想要确定原型与实例之间的关系可以使用instanceof操作符,判断实例化的对象与构造函数之间是否存在联系,可以使用isPrototypeOf()方法,判断构造韩式不是不是实例化对象的原型
这里需要注意的是,给原型添加方法的代码一定要放在替换原型语句之后,否则后面实例化的对象有可能获取不到上面定义的方法。

通过原型链实现继承方法的时候,一定不能使用对象字面量的写法创建原型方法,因为对象字面量会重写该构造函数原型,使其prototype指针指向别处,而非已经定义好的原型链。

无论这种对象字面量设定原型写在哪儿,都不合适。当原型的对象字面量写在原型链形成的语句之后,前面形成原型链的语句会失效;而写在形成原型链的语句之前,会导致后面再次指定原型链时覆盖前面已经声明的原型对象字面量

缺点:
原型链最大的缺点就是在前面原型中写出的共享特性。并且单纯的使用原型链的继承方法,没有办法在不影响所有对象实例的情况下给超类型的构造函数传递参数

2.借用构造函数
这种继承方法的核心就是通过call或者apply方法对函数的执行环境进行一个转移,使其子函数能够通过call/apply方法获取到父函数的属性/方法

function Sup(){
    this.colors = [“blue”, “yellow”, “apple”];
}
function Sub(){
    sup.call(this);
}
var person = new Sub();
person.colors.push(“black”);
console.log(person.colors);                       //blue, yellow, apple,black

使用这种方法也可以通过call/apply()方法实现传递参数的目的,这里需要注意一下call和apply传递参数的不同

缺点:
因为在方法中使用的call/apply方法是一种写死的固定方法,不具备代码复用的特性,所以很少单独使用

3.组合继承
组合继承的核心就是将原型链的集成方法和借用构造函数的方法进行组合使用。原型链方法负责实现对原型方法的继承和复用,借用构造函数方法实现对于实例属性的继承。

function SuperType(name){
    this.name = name;
    this.colors = [“red”, “blue”, “green”];
}
SuperType.prototype.sayName = {
    console.log(this.name);
}
function SuberType(name, age){
    SuperType.call(this, name);   //实现借用构造函数继承
    this.age = age;
}
SuberType.prototype.sayAge = function(){
   Console.log(this.age);
}

SuberType.prototype = new SuperType();           //实现原型继承
SuberType.prototype.constructor = SuberType;     //这里因为是重新进行了prototype的定向,所以原有的constructor属性指向了Object

var person = new SuberType(“abc”, 12);
person.colors.push(“black”);
console.log( person.sayName()+”,”+person.sayAge() );  //abc, 12

4.原型式继承
原型式继承的核心就是一个传入的对象,作为构造函数的原型,在函数的内部创建一个函数,该函数的原型获取到该对象,返回该函数的实例。
但是想要使用这种继承方法必须有一个对象作为另一个对象的基础。(个人不推荐这种继承方式 )

function object(o){
    function F(){ };
    f.prototype = o;
    return new F();
}
var person = {
    name: “abc”,
    colors: [“red”, “green”, “blue”]
};
var conperson = object(person);
conperson.name;                     //abc
conperson.colors.push(“black”);  
console.log(conperson.colors);      //red, green, blue, black

5.寄生式继承
寄生式继承和原型式继承的思路是一样的,这两种方法也都是克罗克福德推广的。
寄生式继承的核心就是接收一个对象参数,通过调用函数创建一个新对象,在内部使用这个新对象创建某些属性和方法,最后返回该对象。(这种模式也不建议使用,构造的方法和前面的原型式继承一个思路)

function createAnother(o){
    var clone = object(o);
    clone.sayHi = function(){
        console.log(“hi”);
	}
return clone;
}
var person = {
    name: “abc”,
    colors: [“red”, “green”, “blue”]
}

var conperson = createAonther(person);
conperson.sayHi();                         // hi

6.寄生组合式继承:
组合继承是JavaScript中最常用的一种继承模式,但是组合继承无论在什么情况下的都会调用两次超类型的构造函数,一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

function SuperType(name){
    this.name = name;
}
superType.prototype.sayName = {
    console.log(this.name);
}
function SuberType(name, age){
    SuperType.call(this, name);             //这里是第二次调用
    this.age = age;
}
Suber.prototype.sayAge = function(){
    console.log(this.age);
}
SuberType.prototype = new SuperType();       //这里是第一次调用
SuberType.prototype.constructor = SuberType; 

为了解决这种重复调用的问题,出现了寄生组合式继承,这也是目前为止最接近完美状态的继承方法
寄生组合式继承

function inherPrototype(subType, supType){         //实现sub和sup的继承关系
	var person = Object(supType.prototype);        //获取到sup这个父函数的原型
	person.constructor = subType;                  //将sup父函数的原型的constructor属性指向给sub函数
	subType.prototype = person;                    //将sub子函数的原型指向sup父函数的原型
}
//父函数
function SuperType(name){
	this.name = name;
	this.colors = ["red", "green", "blue"];
}
SuperType.prototype.sayName = function(){
	console.log(this.name);
};
//子函数
function SubType(name, age){
	SuperType.call(this, name);
	this.age = age;
}
inherPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
	console.log(this.age);
};

var wapper = new SubType();
wapper.name = "bac";
wapper.age = 12;
wapper.sayName();
wapper.sayAge();

猜你喜欢

转载自blog.csdn.net/Feng_ye__/article/details/89352774