学习一波阮一峰的博客 戳这里javascript
博客中是本身的理解,以及对大佬描述不清楚的地方进行了修正,也算是本身的一个再(xiao)产(tu)出(cao)吧html
上一篇:JavaScript面向对象之一(封装)java
先来看个简单的:bash
function Animal(){
this.type = 'animal;'
}
function Cat(name, color){
this.name = name
this.color = color
//这里用call,我的以为更好些
Animall.call(this)
}
var cat = new Cat('po', 'orange')
console.log(cat.type) //animal
复制代码
建立了一个Animal和Cat构造函数,而后在Cat里面调用Animal的构造函数,在将Cat实例化,就能够访问到Animal的属性了。 这个例子显然有问题,放在第一个就是用来找茬的。函数
什么问题呢?假如我想使用在Animal上的公共方法,像这样Animal.prototype.eat = function(){ console.log('animal eat') }
,用cat.eat()
是访问不到的。post
为何呢?由于咱们Cat和Animal的原型根本就没有关联起来呀。你看看我们上面的代码,那个地方关联过?学习
那下面咱们就将二者的原型关联起来试试看ui
function Animal(){
this.type = 'animal;'
}
Animal.prototype.eat = function(){ console.log('animal eat') }
function Cat(name, color){
this.name = name
this.color = color
}
Cat.prototype = new Animal()
var cat = new Cat('po', 'orange')
console.log(cat.type) //animal
console.log(cat.eat()) //animal eat
复制代码
这种方法好!能够拿到属性和方法,一箭双雕。可是,这里有个陷阱(keng)!!!Cat.prototype = new Animal()
以后,咱们的Cat.prototype里面的全部方法都消失了!这是怎么回事?由于new,new作了四件事,这里再次回顾一下:this
var temp = {}
temp.__proto__ = Animal.prototype
Animal.call(temp)
return temp
复制代码
看到了吗?new会使用一个空对象而且将其返回。这样一来咱们的Cat.prototype就被清空了(包括自身的constructor)。因此咱们须要本身多作一件事Cat.prototype.constructor = Cat
。spa
若是咱们不这样作,那么Cat.prototype的构造函数会是什么?咱们在去看看new作的第二件事,这个空对象指向了Animal.prototype,因此Cat.prototype自身若是没有constructor属性的话就会去Animal.prototype上面去找。Cat.prototype.constructor === Animal //true
因此,若是咱们替换了prototype,须要手动去纠正它。
既然上面这种方法有坑,并且的的确确让你很容易漏掉,那咱们改进一下:
function Animal(){}
Animal.prototype.eat = function(){ console.log('animal eat') }
Cat.prototype = Animal.prototype
Cat.prototype.constructor = Cat
var cat = new Cat('po', 'orange')
console.log(cat.eat()) //animal eat
复制代码
既然咱们想从Animal.prototype上面那东西,直接从上面拿不就好了?并且我还机智的填了上面会出现的坑。同时结果也是我想要的。
可是!!咱们的Cat.prototype和Animal.prototype指向的是同一个原型,这会致使我在Cat.prototype上作了什么事,会同时发生在Animal.prototype上。这是为何呢?MDZZ,这两个就是同一个东西呀,原型是堆中一块内存,Cat和Animal都指向这块内存,操做的是同一个东西,怎么会不影响?
与此同时,自觉得聪明的填坑Cat.prototype.constructor = Cat
,此时的Cat和Animal的原型是同一个,修改了constructor以后,致使Animal的constructor变成了Cat。这种方法果断PASS。。。
var F = function(){}
F.prototype = Animal.prototype
Cat.prototype = new F()
Cat.prototype.constructor = Cat
复制代码
咱们使用中间对象进行过分,巧妙的将Cat.prototype和Animal.prototype解耦,这样就不会出现问题了。仔细观察会发现这个和new作的事情有殊途同归之处。
咱们进行封装一下在使用
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
extend(Cat,Animal);
var cat1 = new Cat('po' 'orange');
alert(cat1.eat()); // animal eat
复制代码
这里Child.uber = Parent.prototype
的意思相似于__proto__
。
这里还有一种简单粗暴的方式
function extend2(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
}
function Animal(){}
Animal.prototype.eat = function(){ console.log('animal eat') }
extend2(Cat, Animal);
var cat1 = new Cat('po' 'orange');
alert(cat1.eat()); // animal eat
复制代码
直接遍历父类的原型,一个个复制到子类原型上便可。
感慨一下,大佬仍是大佬呀。。。