闲话少叙,继续讲单身狗的故事。
动物,单身狗
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);