继承
今天给大家科普一个叫做继承的大哥。之所以叫做大哥,是因为他确实是所以语言都必须具备的。而且这也是BAT公司前端面试中,必提及的一个知识点。 由于js 是由 大神 在10天之内写完了,但后来由ECMA262接手优化,最终有了现在丰满的JS。 但是关于继承的遗留问题应该算是比较严重的。 先说一下基本的js继承有哪些.
借用构造函数
啊~~~ md, 名字怎么这么怪嘞! 这个官方的说法,我们乡下人管他叫做复制(copy);
来个栗子:
function Father(name){
this.name =name;
}
function Children(name){
Father.call(this,name);
}
let jimmy = new Children("jimmy");
console.log(jimmy.name); //jimmy
没错,看清楚,其实就是使用了函数对象自带的方法。call 来创建的。 将父构造函数的属性给copy到子类上,相当于建立了一个副本。但其实这种方式并没有什么卵用。 和我前一篇说过,构造函数模式不流行就是因为他的重用性 === 0. 这种继承方式的重用性(呵呵) <=0. 但是我们也不能否定他的存在,毕竟我以前也用过。
介绍一个当今比较流行的,组合继承
组合继承
组合就是融合了原型和构造器的一种继承方法。 这个应该算是一种比较稳妥的继承方式.
即能排除引用类型造成的问题,又可以实现共享的效果。
function A (){
this.name = "jimmy";
}
A.prototype.speak = function(){
console.log(`my name is ${this.name}`);
}
function B(){
A.call(this);
}
B.prototype = new A();
B.prototype.constructor = B;
var b = new B();
console.log(b.name); //jimmy
b.speak(); //my name is jimmy
这种应该算是比较经典了,但这样会两次调用到父类型,对内存影响还是比较大的。 所以有人提出中间创建一个寄生组合式继承. 但这个真的很鸡肋。 JS的一个继承能扯出这么多东西,也是醉了。
但是es6 class 的出现,解决了这一痛点。 虽然这个东西有悖js 的原理(因为在js中是没有类这个概念的),但是实用性确实相当的好.
所以今天的主角应该是class 这个东西
class
在es6中新出了一个feature--class. 中文叫做类. 应该算是混合模式的一个总结吧。在使用class的使用,你完全可以不去写,constructor, prototype之类的东西了.
来个栗子:
//原生的混合模式:
function Point(x,y){
this.x = x;
this.y = y;}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
}
var point = new Point(1,2);
//使用class的类:
class Point {
constructor(x, y) { //本质上还是原型链上的方法
this.x = x; //这里的this和上面的一样都代表实例对象
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
var point = new Point(1,2);
虽然我打心里是不愿意将类加入js里面(没准以后就变为标准了),但为了大家的理解,我还是把这个称为类吧; ):
可以看到类和原型js的写法的不同吧。我先说一下语法吧。
创建一个类,就和在java里面创建类是一样的。
初始化使用class + 类名(首字母大写) + {...}
class Hehe{
...
}
var hehe new Hehe();
初始化话,上面也已经说了。在类中需要注意一个叫做constructor的方法,这个就相当于构造函数里面的内容,他会在类初始化时,自动执行. 所以可以在constructor里面传递一些参数.
class Jimmy{
constructor(name){
this.name = name; //这里的this和构造函数里面的this的属性是一致的
}
}
let jimmy = new Jimmy("jimmy");
console.log(jimmy.name); //jimmy
当然在类中还可以添加方法。具体做法如下:
class Jimmy{
constructor(name){
this.name = name; //这里的this和构造函数里面的this的属性是一致的
}
speak(){
console.log(`my name is ${this.name}`);
}
}
let jimmy = new Jimmy("jimmy");
jimmy.speak(); //my name is jimmy;
需要注意,请不要手贱在每个{} 后面加上 "," 像这样
class Jimmy{
constructor(name){
this.name = name;
},
speak(){
console.log(`my name is ${this.name}`);
}
}
到时候出个bug, 我看你哭去吧。
而这样定义的方法其实是存在于Jimmy.prototype 上的。
我们检验一下Jimmy的类型;
Jimmy instanceof Function; //true
所以说 其实 类就是js混合模式的一个syntax candy(语法糖).
当然类也可以使用字面量形式书写(废话,类本来就是函数类型)
const MyClass = class Me {
getClassName() {
return Me.name; //这里的Me 就和使用函数是一样的道理
}};
var MyClass = function Me(){
console.log(Me.name); //Me
}
关键看你喜欢用哪一种了。
说一说类的继承吧, 这应该是我最喜欢class的原因了.
class的继承
在class中是使用extends来实现继承的效果的. 还有一个特性 super. 这个用来指向父类的实例,如果大家记得应该会了解到上面说的继承模式吧。 而这里的super算是es6新定义的一个东西。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
this.color = color; // 这里会报错,ignore这句就可以了
super(x, y); //这里相当于初始化父类,然后规定class里面this的指向
this.color = color; // 正确
}
show(){
console.log(this.color);
console.log(super.x);
console.log(this.x);
}
}
var color = new ColorPoint(1,2,"red");
color.show();
//依次得到, red , 1 ,1
我艹,super和this到底应该怎么区分嘞?
很简单,上面已经说了,super是指向父类的实例,而this是在这里是构造函数上原型的指针。 其实由于继承,使用this也可以访问到x; 所以推荐如果你有强迫症的话,父类上的方法和属性可以使用super调用,子类自定的属性和方法使用this调用。 当然我喜欢直接使用this(三包服务)。
还有一点,那我怎么检测我的父类到底是谁嘞(隔壁王叔叔)?
如果你在浏览器的Console 里面,可以直接使用.__proto__来进行检测的(脚本里不行)。在脚本里,js提供了一个方法getPrototypeOf()来进行检测
//上述例子
Object.getPrototypeOf(ColorPoint); //Point
//相当于浏览器里面的
ColorPoint.__proto__; //Point
关于继承我就扯这么多吧。 虽然说继承很重要,但我们用的地方不是很多,原因是----因为我们不牛逼。。。 大家如果有空可以去翻一翻jquery或者zepto的源码,看一看是不是用到了prototype,继承等相关的技术。而且他们封装性都是超级好的。没有一个直接写在全局里面的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。