原型-原型链-继承

原型:

是function对象的一个属性,它定义了构造函数 制造出的对象 的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象

这定义有点模糊,用代码解释一下

function Foo () {}
var son = new Foo();
console.log(son)


我们在控制台中打印出了这个,首先son对象的构造函数是Foo,但是我们的Foo中什么属性都没有,怎么会出现一个__proto__呢?

因为我们使用了new操作符,会隐式的创建一个 this={ } 对象,这个this中有一个__proto__属性,这个属性的值就是Foo的原型,这个原型通俗点说,就是son的父亲

假如son的父亲有一个name属性,son就可以继承这个name属性,看下面代码

Foo.prototype.name = 'xxx'
function Foo () {}
var son = new Foo();
console.log(son)
console.log(son.name)

我们Foo中并没有name这个属性,但是Foo的原型上有,我们依然打印出了 ‘xxx’

上面定义说了,原型本身就是一个对象,现在除了name这个新添加的属性,还有两个属性,constructor和__proto__

constructor属性,这个属性是构造器,指向构造方法本身,所以我们能使用这个Foo方法

__proto__我们上面说,这个属性是指原型,难道这son的的父亲Foo.prototype还有父亲?对的,Foo.prototype的父亲是Object.prototype

这上面定义了一些原始方法供我们调用,但是我们发现,这里面没有__proto__这属性了,也就是说,Object.prototype就是原型的终点了

原型链:

GrandFoo.prototype.name = 'xxx';    //在爷爷的原型上加一个name属性
function GrandFoo () {}
var GrandFoo = new GrandFoo();

Foo.prototype = GrandFoo;           //父亲的原型变为爷爷
function Foo (){
	this.sex = 'male';
}
var foo = new Foo()

Son.prototype = foo;                //儿子的原型变为父亲
function Son (){
	this.age = 18;
}
var son = new Son()

console.log(son.age)
console.log(son.sex)
console.log(son.name)

打印结果是   18       male         xxx

首先打印儿子的年龄,他自己的构造函数中有age,直接打印出来

然后打印儿子的性别,他自己的构造函数中没有,然后去找儿子的原型,儿子的原型由系统默认的改为父亲了,所以到父亲的构造函数上找sex属性,然后打印出来

最后打印儿子的名字,他他自己的构造函数中没有,然后找父亲的构造函数,也没有,然后找父亲的原型,也就是爷爷,还是没有,然后找爷爷的原型,爷爷的原型是系统默认的,我们在这里面添加了一个name属性,所以儿子找到了这个属性,就打印出来了

继承的演变:

1.   传统形式

原理:Son继承Foo,继承Foo.prototype.

缺点:

不能随便给自己原型增添属性

过多的继承了没用的属性

Foo.prototype.name = 'ss';   		//给Foo的原型添加一个属性name
function Foo () {     			//构造函数
	// this{
	// 	__proto__:Foo.prototype;
	// }
}
var son = new Foo()             	//使用new操作符创建一个新对象,son对象的构造体就是Foo
console.log(son.name);	
当使用new操作符时创建的新对象中,会有一个隐式的this对象,this对象中有一个__proto__属性,指向该对象的原型

我们打印son.name时,它会到自己的构造体Foo()中找name属性,但是Foo()中没有,就通过this下的__proto__找到原型,在原型上找到了name属性,于是可以打印出name

2.   借用构造函数

原理:Foo构造出自己的函数,内有许多属性和方法。Son通过改变this的指向,从而借用Foo函数内的属性、方法

缺点:

没有实现真正的继承,不能继承构造函数的原型

每次构造函数都要多走一个函数

function Foo (name,age) {
	this.name = name;
	this.age = age;
}

function Son (name,age) {
	//this = {}
//call方法:第一个参数用来改变this指向,后面的参数是形参,我们这句话是把Foo的this改为Son的this	
//现在Son就有了name和age属性,然后执行Foo这个函数,把实参传入之后,就可以打印出值
	Foo.call(this,name,age)     
}
var son  = new Son('x',19);    	    //再创建一个对象son,传入实参

console.log(son.name)

3. 共享原型

原理:P对象将共有原型贡献出来以便C使用。C和P共享一个共同的原型。

缺点:

不能随便改动自己的原型

P.prototype = {
	name:'1xx',
	age:19
}
function P () {}
C.prototype = P.prototype;
function C () {}
var c = new C()

console.log(c.name)

4.   圣杯模式

原理:在P.prototype和C之间再加入一个中间层F,当改变C.prototype时不会改动P.prototype。解决了共享原型的缺点。

//圣杯式继承方法
var inherit = (function(){
	var F = function(){}      				//创建一个中间层F
	return function(C,P){
		F.prototype = P.prototype;   		//把P的原型给F
		C.prototype = F.prototype;   		//把F的原型给C
		C.prototype.constructor = C;  		//C的构造器会因为上面改变原型变乱,所以要指回自己
		C.prototype.uber = P.prototype;		//做一个备份,把P原型给C的原型上添加一个uber属性,
	}
}())

Foo.prototype.name = 'xx'
function Foo () {}
function Son () {}
inherit(Son,Foo)
var son = new Son()

console.log(son.name)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值