JavaScript之原型继承prototype

JavaScript的原型链,之前也用过,但对其中的原理一直没有深究,这次通过学习node.js,然后再回过头来系统的学习JavaScript,发现JavaScript的原型链机制是一个十分有趣的机制

我们都知道,JavaScript的对象机制和C类语言是由很大区别的,而其中一个很大的区别就是JavaScript是使用原型链来实现继承的


一. 原理

prototype是JavaScript对象的一个属性,注意这里是对象,而不是对象实例

var x = function(){};
console.log(typeof x.prototype); //object
console.log(typeof (new x()).prototype); //underfined

var y = {};
console.log(typeof y.prototype); //underfined
console.log(typeof Array.prototype); //object

可以看到,对象实例化之后,就不再包含prototype这个属性了,所以y.prototype = xxxx;是没有意义的,就只是多了一个prototype属性而已,而这个属性是不属于JavaScript内部的原型链机制的

另外,当要给原型赋值的时候,等号的右边一定是一个实例化好的对象,这就像C++的继承机制,当实例化一个类时,首先要实例化他的父类,所以等号右边就相当于是已经实例化好的父类,比如:

var x = function(){};
var y = function(){};
y.prototype = new x(); //等号右边是一个实例化好的父类

看看下面一张图:


可以看到,左边对象的prototype指向右边对象实例,而对象实例通过一个私有属性proto来访问父类,而Object对象是JavaScript的根对象,所以它的prototype指向一个空的对象实例,这就是JavaScript原型继承的机制



二. 使用

1.继承

var x = function(){};
var y = function(){};
y.prototype = new x();
y.prototype.print = function() {
	console.log("I get it!");
};
(new y()).print(); //I get it!


这样,y就继承了x的print函数,属性也是如此
不过要注意,y只能继承对y.prototype所添加的属性和方法,比如下面的继承是无效的:

var x = function(){};
var y = function(){};
x.print = function() {
	console.log("I get it!");
};
y.prototype = new x();
x.print(); //I get it!
(new x()).print(); //报错
(new y()).print(); //报错
为什么会错呢,一般只会对对象的实例添加属性和方法,而不会对对象添加属性和方法,否则,只有对象本身能够访问该方法,而对象的实例是访问不到的,更不用说继承了

另外,想要继承函数内部的方法要格外小心,先看一个例子:

var x = function(){
	var print = function() {
		console.log("I get it!");
	}
};
var y = function(){};
y.prototype = new x();
x.print(); //报错
(new x()).print(); //报错
(new y()).print(); //报错
为什么会错呢,因为在函数内部通过var定义的方法或者直接定义的方法都是私有的,外界是访问不到的,也不能继承,换成

function print() {
	console.log("I get it!");
}
也一样

再看另一个例子:

var x = function(){
	this.print = function() {
		console.log("I get it!");
	}
};
var y = function(){};
y.prototype = new x();
x.print(); //报错
(new x()).print(); //I get it!
(new y()).print(); //I get it!
这里使用了this关键字,对于this关键字,以后会详细说明,这里只需要知道,new x()的时候,this指向了新创建的对象实例本身,然后对这个对象实例本身添加了一个print方法,机制和第一个例子一样,就是写法稍微不同而已

2.节省空间和提高效率

对一个对象添加方法,一个直接的写法是:

var x = function(){
	this.print = function() {
		console.log("I get it!");
	}
};
(new x()).print(); //I get it!
但一般不会这么写,而是这样写:

var x = function(){};
x.prototype.print = function() {
	console.log("I get it!");
};
(new x()).print(); //I get it!
这样在创建对象x 的实例的时候,就不会重复地创建相应的方法和属性,所有通过new x()创建出来的对象实例都会继承x.prototype的方法和属性,比如这里创建出来的x对象实例都是空的,但是他们却能在需要的时候调用print()函数,所以,提高了运行效率(但是在不断搜寻原型链的时候也会耗费时间,所以原型链不宜过长)


PS:这里的几个例子都用了new 函数名()的方法来创建一个对象实例,其实这种方法在很多书上是不被推荐使用的,因为new方法只是JavaScript原型链继承机制向C类继承机制靠拢的一个手段,结果就是:It is the worst of both worlds

3.扩展原有的类库函数


由于JavaScript可以很方便地向一个对象添加方法,所以,我们可以对基本对象的原型添加方法,那么,所有继承这些基本对象的对象实例就将拥有这些方法
比如,我想给Number对象添加一个取整的方法:

Number.prototype.integer = function() {
	return Math[this < 0 ? 'ceiling' : 'floor'](this);
};

之后就可以在所有的继承于Number对象的实例处使用这个方法了

console.log((10 / 3).integer()); //3

当然,扩展类库函数并不是特别推荐使用,因为有人说这样会破坏封装,而且还要特别注意函数是否已经被声明过,不过,这样写的确会简化某些操作


三. 一些很好的文章

1.浅析Javascript原型继承   这篇文章对JavaScript原型继承有一个很好的讲解

2.JavaScript秘密花园 这篇文章对JavaScript的语法机制有一个全面系统的讲解,十分推荐!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值