闲话少叙,继续讲单身狗的故事。
动物,单身狗
function Animal(){
this.type = "动物";
}
function Dog(name) {
this.type = '动物';
this.name = name;
}
我们知道,单身狗是一种动物,那么工厂怎么来表示这种继承关系呢?
1. 进化方式1(构造函数绑定)
function Animal(){
this.type = "动物";
}
function Dog(name) {
Animal.call(this); // Animal.apply(this); 也可以
this.name = name;
}
var dog = new Dog('单身狗');
console.log(dog.name, dog.type); // 单身狗 动物
2. 进化方式2(prototype模式)
前提知识:
原型链继承方式最终表达为:
var dog = new Dog();
// 获得父类和爷爷类方法如下
dog.__proto__.__proto__.__proto__;
2.1 那么 __proto__ 这个是怎么来的呢?
// 实例的__proto__是引用构造函数的prototype
dog.__proto__ === Dog.prototype; // true
按照上面代码的逻辑父类应该怎么继承就变成了这样:
Dog.prototype.__proto__ === Animal.prototype; // true
那么怎样达到上面代码的效果呢?
Dog.prototype = new Animal();
这种方式有什么问题?
每个prototype都有一个constructor,指向构造方法本身:
Dog.prototype.constructor === Dog; // true
执行以上代码后就变成了:
Dog.prototype.constructor === Animal; // true
这样就破坏了构造方法的基本结构。
为什么会变成这样?
实际上调用方法内部是这样执行的:
1.先在Dog.prototype上查找 constructor 属性,实际上没找到;
2.再在Dog.prototype 的原型链查找上一级原型是否含有这个属性 Dog.prototype.__proto__.constructor ;
3.发现有一个叫做 constructor 的属性,然后返回这个属性。
怎么解决?
// 加一句
Dog.prototype.constructor = Dog;
完整版:
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
var dog = new Dog();
完美!
2.2 思考另外一种方法
// 是否可以这样实现子类继承父类?
Dog.prototype = Animal.prototype;
Dog.prototype.constructor = Dog;
var dog = new Dog();
测试:
Animal.prototype.constructor === Dog; // true
问题:
改掉了父类的构造方法。
2.3 终极继承大法!
var F = function(){};
F.prototype = Animal.prototype;
Dog.prototype = new F();
Dog.prototype.constructor = Dog;
优点:
节能环保
3. 彩蛋
new Dog() 被执行时干的活:
1. Dog 方法内创建一个对象, this指向这个对象;
2. this.__proto__ = Dog.prototype;
3. 执行 Dog方法内的逻辑;
4. 方法最后一定返回一个对象。分以下几种情况
- 如果没有
return,则返回this。- 如果有
return,且return返回的是一个js的原始数据,方法返回this。反之,方法返回return关键字后面的对象。
var self;
function foo(){
self = this;
this.name='a';
}
foo.prototype.getName = function() {
return this.name;
}
var f = new foo();
console.log(f === self);
本文深入探讨JavaScript中实现继承的多种方式,包括构造函数绑定、原型链继承等,并详细解析每种方式的工作原理及其优缺点。

被折叠的 条评论
为什么被折叠?



