JS的继承
拖了很久的JS继承终于来个总结了T^T
本篇文章参考阮一峰老师的博文。一共有三篇。
一、先说一下prototype对象
function Cat(name, age){ this.name = name; this.age = age; this.speak = function () { console.log(this.name + ' miao'); } } var cat1 = new Cat('Tom', 1); var cat2 = new Cat('John', 2); console.log(cat1.speak()); // Tom miao console.log(cat2.speak()); // John miao
上面代码中的两个实例,cat1 和 cat2 都有自己的name属性,age属性,speak方法,但是其实speak方法实可以共用的,这样就会造成了资源浪费。避免这种浪费,我们可以把 speak 方法写入构造函数的 prototype 对象中。
function Cat(name, age){ this.name = name; this.age = age; } Cat.prototype.speak = function(){ console.log(this.name + ' miao'); } var cat1 = new Cat('Tom', 1); var cat2 = new Cat('John', 2);
将可以共享的方法挂载在原型对象上,就可以避免出现内存浪费的现象了
Cat.prototype.speak = function() { console.log(this.name + ' miao'); } Cat.prototype.eat = 'fish'; cat2.prototype.eat = 'meat'; // 问题来了,如果我改变其中一个实例的原型上的属性和方法,那么另一个原型会不会收到影响呢
答案是不会!!!
但是,如果修改的是 cat2.__proto__.eat,那么就会对 cat1 有影响了
这里可能有点迷!!!是的,我有点迷~~~~~~~
我是这样子理解的
因为创建实例需要用到 new 操作符,那么 new 中间作了什么妖呢
- 创建了一个新对象
- 将新对象的__proto__属性指向构造函数的原型对象,新对象就新增了构造函数原型对象上的属性和方法
- 将构造函数的this指向替换成新对象,再执行构造函数,这样新对象就新增了构造函数本地的属性和方法了
// 模拟 new var obj = {}; obj.__proto__ = 构造函数.prototype; 构造函数.apply(obj);
那么看会又来的构造函数 Cat,我画了这样一幅图
二、JS继承
- 原型链继承——将父类的实例作为子类的原型
function Animal(name){ this.name = name; } Animal.propotype = { canRun: function(){ console.log(this.name + ' can run.'); } } function Cat(){ this.speck = 'miao'; } Cat.prototype = new Animal('Tom'); Cat.prototype.constructor = Cat;
我觉得应该会有人有和我一样的疑惑。为什么会有Cat.prototype.constructor = Cat的出现。
因为我们把父类Animal的实例作为了子类Cat的原型对象,因此如果没有Cat.prototype.constructor = Cat,Cat.prototype.constructor就会指向Animal,造成继承链的混乱,所以我们需要手动纠正。
2. 构造继承——改变this的指向,用apply或者call方法实现
function Animal(name){ this.name = name; } Animal.prototype = { canRun: function(){ console.log(this.name + ' it can run!'); } } function Cat(name){ Animal.call(this, name); this.speak = 'miao'; }
var cat1 = new Cat('Tom');
这个继承方法有一个不好,就是子类无法继承父类原型上的属性和方法,也就是说 cat1.canRun()会出错。
3. 组合继承——将原型链继承和构造继承结合到一块
function Animal(name){ this.name = name; } Animal.prototype = { canRun: function(){ console.log(this.name + 'is can run!'); } } function Cat(name, age){ Animal.call(this, name); this.speak = 'miao'; this.age = age; } Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; var cat1 = new Cat('Tom', 12);