资讯专栏INFORMATION COLUMN

js痛点之继承

fantix / 996人阅读

摘要:和我前一篇说过,构造函数模式不流行就是因为他的重用性这种继承方式的重用性呵呵但是我们也不能否定他的存在,毕竟我以前也用过。

继承

今天给大家科普一个叫做继承的大哥。之所以叫做大哥,是因为他确实是所以语言都必须具备的。而且这也是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,继承等相关的技术。而且他们封装性都是超级好的。没有一个直接写在全局里面的。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78392.html

相关文章

  • vue(1)-学习历程vue解决jquery的什么痛点

    摘要:解决的痛点首先我们需要明白和理解和的设计初衷和理念。所有框架要解决的问题应对需求变化,防止大面积重写。参考文献渐进式框架理解核心功能原理解析百度网盘视频学习以及源码资源提取密码 vue解决jquery的痛点 首先我们需要明白和理解jquery和vue的设计初衷和理念。 jquery官网给出的开篇介绍是,jquery是一个快,小,功能丰富的js库,它让html文档遍历和操作,事件处理...

    zhaofeihao 评论0 收藏0
  • 如何在前端代码中,应用面向对象的编程范式?

    摘要:为什么要面向对象你需要知道的面向对象面向对象并不是针对一种特定的语言,而是一种编程范式。后端传递过来显示工人完成状态的字段代表未完成,代表已完成。其实这就是如何消除代码副作用的问题将副作用隔离。 为什么要面向对象? 你需要知道的面向对象 面向对象并不是针对一种特定的语言,而是一种编程范式。但是每种语言在设计之初,都会强烈地支持某种编程范式,比如面向对象的Java,而Javascript...

    NeverSayNever 评论0 收藏0
  • 《Node.js在CLI下的工程化体系实践》成都OSC源创会分享总结

    摘要:之后,在本地目录生成代码并且安装项目依赖的包,最后将本次初始化生成的所有代码自动提交到远程仓库。按照城市评选,分别评选明日之子仅限男性参加和闪亮女神仅限女性参加。 背景: 随着开发团队规模不断发展壮大,在人员增加的同时也带来了协作成本的增加,业务项目越来越多,类型也各不相同。常见的类型有组件类、活动类、基于React+redux的业务项目、RN项目、Node.js项目等等。如果想要对每...

    imingyu 评论0 收藏0
  • CSS module 入门

    摘要:示例库通过记录来查看定制类名默认的哈希算法是,从前面我们可以发现被编译成了这样的字符串。与上面不加等价显式的局部作用域语法通过示例库的记录来查看下的样式复用对于样式复用,提供了组合的方式来处理。 showImg(https://segmentfault.com/img/bV9WfX?w=800&h=274);前端发展越来越快,这应该是每个前端开发者的切身感受,但是CSS 是前端领域中进...

    warnerwu 评论0 收藏0

发表评论

0条评论

fantix

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<