JavaScript4.2

6.3.1 原型链
许多OO 语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。
由于函数没有签名,在ECMAScript 中无法实现接口继承。ECMAScript 只支持实现继承,而且其实现继承主要是依靠原型链来实现的。

//以下理解错误!  
以下三点需要谨记

1.每个对象都具有一个名为__proto__的属性;

2.每个构造函数(构造函数标准为大写开头,如Function(),Object()等等JS中自带的构造函数,以及自己创建的)
都具有一个名为prototype的方法(注意:既然是方法,那么就是一个对象(JS中函数同样是对象),所以prototype同样带有__proto__属性);
对象并不具有prototype属性。
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype
属性,这个属性指向函数的原型对象

3.每个对象的__proto__属性指向自身构造函数的prototype(指向自身构造函数的原型对象);

__proto__这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。

再次理解原型属性,原型对象
1.isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型
2.ECMAScript 中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性:length 和prototype。
3.prototype 是保存它们所有实例方法的真正所在。诸如toString()和valueOf()等方法实际上都保存在prototype 名下,只不过是通过各自对象的实例访问罢了,prototype 属性是不可枚举的,因此使用for-in 无法发现。
4.我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
如果按照字面意思来理解,那么prototype 就是(个人理解:相当于是,其实不是,prototype属性是一个指针,指向原型对象)通过调用构造函数而创建的那个对象实例的原型对象。
使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。

5.只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype 属性所在函数的指针。
原型对象最初只包含constructor 属性,而该属性也是共享的,因此可以通过对象实例访问。
//个人理解: 该函数的prototype(原型)属性 ,指向该函数的原型对象。
该函数的原型对象 ,包含一个constructor(构造函数)属性。
constructor(构造函数)属性,包含一个指向 prototype 属性所在函数的指针。

6.创建了自定义的构造函数之后,其原型对象默认只会取得constructor 属性;至于其他方法,则
都是从Object 继承而来的。
当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性)(+①),指向构造函数的原型对象。
__proto__这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。

①这个指针叫[[Prototype]] 或__proto__ //个人理解:可称为实例属性

test

看懂上述 构造函数、原型对象和实例的关系后在看继承:
实现原型链有一种基本模式,其代码大致如下。

//父类构造函数对象
function SuperType(){
	this.property = true;
}
//父类原型对象属性 增加方法function
SuperType.prototype.getSuperValue = function(){
	return this.property;
}


//子类构造函数对象
function SubType(){
	this.proper = false;
}

//子类原型对象 变更为父类对象实例。 
//上下文通过这句话SuperType和SubType形成了父子关系,SubType继承了SuperType.
//实现的本质是重写原型对象,代之以一个新类型的实例。
换句话说,原来存在于SuperType 的实例中的所有属性和方法,现在也存在于SubType.prototype 中了。
SubType.prototype = new SuperType();
(新原型SubType.prototype不仅具有作为一个SuperType 的实例所拥有的全部属性和方法,而且SuperType 的实例内部还有一个指针,指向了SuperType 的原型。)

//子类原型对象属性 在继承了SuperType 的属性和方法的基础上又添加了一个新方法function
SubType.prototype.getSubvalue = function(){
	return this.property;
}

var instance = new SubType();
alert(instance.getSuperTypeValue()); //true

//1.子类实例instance 先在子类中找 getSuperTypeValue没有找到,
2.然后再去原型对象中找, 子类的原型对象被替换成了父类的实例,
则在父类的实例中找 getSuperTypeValue, getSuperTypeValue没有找到,
3.然后再去父类的原型对象找getSuperTypeValue,
最终在父类的原型对象中找到了getSuperTypeValue,
getSuperTypeValue是父类原型对象的属性。

① 实际上,不是SubType 的原型的constructor 属性被重写了,而是SubType 的原型指向了另一个对象——SuperType 的原型,而这个原型对象的constructor 属性指向的是SuperType。

6.3.2借用构造函数 (有时候也叫做伪造对象或经典继承)。
技术的基本思想,即在子类型构造函数的内部调用超类型构造函数。

function SuperType(){
	this.colors = ["red", "blue", "green"];
}
function SubType(){
	//继承了SuperType
	//这行代码“借调”了超类型的构造函数。通过使用call()方法(或apply()方法也可以),
	//我们实际上是在(未来将要)新创建的SubType 实例的环境下调用了SuperType 构造函数。
	//这样一来,就会在新SubType 对象上执行SuperType()函数中定义的所有对象初始化代码。结果,
	//SubType 的每个实例就都会具有自己的colors 属性的副本了

	SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"

6.3.3 组合继承
思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
例子:

//基类函数对象
function SuperType(name){
	this.name = name;
	this.colors = ["red", "blue", "green"];
}
//基类原型对象  增加 函数方法
SuperType.prototype.sayName = function(){
	alert(this.name);
};

//子类函数对象
function SubType(name, age){
	//继承属性,调用基类的构造函数
	SuperType.call(this, name);
	this.age = age;
}
//继承方法,将子类原型对象设置成基类实例对象
SubType.prototype = new SuperType();
//因为子类原型对象现在用的是基类实例对象,所以此时的子类原型对象是没有 构造属性的。
再此我们增加原型对象(基类实例对象)的构造属性 ,指向子类构造
SubType.prototype.constructor = SubType;
//为子类原型对象增加 函数方法
SubType.prototype.sayAge = function(){
	alert(this.age);
};

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29

var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27

这是JavaScript 中最常用的继承模式。而且,instanceof 和isPrototypeOf()也能够用于识别基于组合继承创建的对象。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/baidu_19552787/article/details/84766689
4.2