今天想再深入理解一下原型继承,发现以下这两种继承方式都没什么问题,请问大牛们,这两种方式有区别吗,区别是啥?
function People(){}
People.prototype = {role : 'user'}
function Male(){}
Male.prototype = People.prototype;
var m = new Male()
m.role // 输出 user
m instanceof People // 输出 true
function People(){}
People.prototype = {role : 'user'}
function Male(){}
Male.prototype = new People(); // 这里跟上面定义方式不同
var m = new Male()
m.role // 输出 user
m instanceof Male
巴扎黑2017-04-10 15:21:44
有区别!
原形链不一样。第一个的原型链是:m->People.prototype
,第二个的原型链是:m->{// People实例}->People.prototype
提问者提问:这两种写法除了原型链条上的区别外,如果在运用到实际的工作中,会不会遇到坑?
会!!第一种比较可能遇到坑!看代码:
javascript
// 假设全局存有 EventProxy 构造函数 // 我想让继承 People 的所有实例具有 EventProxy 的事件方法,如: ... var m = new Male(); m.on('beat', function () { console.log('好疼'); }); m.emit('beat'); // =>'好疼'
第一种继承实现:
javascript
function People () { EventProxy.call(this); } function Male () {} Male.prototype = People.prototype; var m = new Male() m.on('beat', function () { console.log('好疼'); }); // 报错!!!,不存有on方法
第二种继承实现:
javascript
function People () { EventProxy.call(this); } function Male () {} Male.prototype = new People(); var m = new Male() m.on('beat', function () { console.log('好疼'); }); // 不报错,正常
当然对于第一种继承实现,也是有方法避免报错的:
javascript
function People () { EventProxy.call(this); } function Male () { People.apply(this, arguments); } Male.prototype = People.prototype; var m = new Male() m.on('beat', function () { console.log('好疼'); }); // 不报错,正常
总结:在javascript的原型继承的世界里,这是十分灵活自由的,所以当然也会存有很多很多的坑。对于很多初学者或小白(比如我)是很难明白那种方法比较正统,也很难明白那种方法比较正确,但这不重要,毕竟这些‘哲理’上的东西需要经验的积累
,但至少需要知道当发生报错时,究竟是什么错并如何解决!
PS:对于第二种继承实现和对第一种继承实现的完善同样是有区别的。
大家讲道理2017-04-10 15:21:44
可以参考下ruanyf
的http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inhe...
PHP中文网2017-04-10 15:21:44
经我思考,Male.prototype = People.prototype
的方式不可用,因为Male继承自People,但是Male还需要具备自身所拥有的属性,如果直接使用 Male.prototype = People.prototype
的方式,未来会污染到父类原型链,比如我给 Male.prototype.role = 'male user'
,那么所有的People.prototype
都被污染了!
因为 Male.prototype
是一个原型引用,改变引用类型,所有的引用都会改变。
因此,Male.prototype = new People()
才是正统!
一个网友建议使用:Male.prototype = Object.create(People.prototype)
我觉得也是赞赞的。
PHP中文网2017-04-10 15:21:44
JavaScript的继承是基于原型链而非“类”,其所谓继承不过是在原型链中查找其本身不存在的属性而已。
目前最有效的设计,是在子类型中调用父类型构造函数,同时指定子类型的prototype属性为一个以父类型的prototype为原型的对象,这样可以构建合理的原型链。
还是拿传统的动物来举例:
function Animal(name) {
if (!(this instanceof Animal)) {
//防止没有使用new调用此函数时污染全局环境
return new Animal(name);
}
this.name = name;
}
Animal.prototype.type = 'Animal';
Animal.prototype.run = function () {
console.log(
this.type + ' ' + this.name + ' is running!'
);
};
如上我们建立了一个Animal类型,其name属性由参数name确定,其实例的原型中的type属性由Animal.prototype.type来确定。
var animalJoe = new Animal('Joe');
animalJoe.run(); // Animal Joe is running!
下面将建立一个Dog类型,继承自Animal:
function Dog(name, color) {
if (!(this instanceof Dog)) {
return new Dog(name, color);
}
Animal.call(this, name); //调用父类型构造函数初始化子类型的实例
this.color = color;
}
Dog.prototype = Object.create(Animal.prototype); //Dog.prototype的原型即Animal.prototype
Dog.prototype.constructor = Dog; //指定构造函数,方便以后使用
console.log(Dog.prototype.__proto__ === Animal.prototype); //true
Dog.prototype.type = 'Dog'; //覆盖了父类型原型中的type属性
var dogJack = new Dog('Jack');
dogJack.run(); //Dog Jack is running!
console.log(dogJack instanceof Animal); //true
console.log(dogJack instanceof Dog); //true
console.log(dogJack.__proto__ === Dog.prototype); //true
console.log(dogJack.__proto__.__proto__ === Animal.prototype); //true
为方便继承可以采用如下函数:
function extend(Pt, St, np) {
//指定原型
St.prototype = Object.create(Pt.prototype);
St.prototype.constructor = St;
//扩展新的原型
for (var i in np) {
St.prototype[i] = np[i];
}
}