题外话

前段时间面试中笔试题有这道题目:

请实现一个继承链,要求如下:

  • 构造函数A():构造函数中有consoleA方法,可以实现console.log("a")

    实例对象 a:a 可以调用consoleA方法

  • 构造函数B():构造函数中有consoleB方法,可以实现console.log("b")

    实例对象 b:b 可以调用consoleAconsoleB方法

  • 构造函数C():构造函数中有consoleC方法,可以实现console.log("c")

    实例对象 c:c 可以调用consoleAconsoleBconsoleB方法

ok,这个题目暂时搁置,再回到这个问题之前,我们先来看看 js 的继承方式

约定

// 父类
function Super() {
this.name = "parent0";
this.colors = ["red", "blue", "yellow"];
}
Super.prototype.sex = "男";
Super.prototype.say = function() {
console.log(" Oh,My God! ");
};

构造继承

原理

通过使用 call、apply 方法可以在新创建的对象上执行构造函数,用父类的构造函数来增加子类的实例

实现

function Sub() {
Super.call(this);
this.type = "sub";
} var s = new Sub(); console.log(s.colors); //[ 'red', 'blue', 'yellow' ]
s.say(); //报错 sub.say is not a function

优缺点

  • 优点:简单明了,直接继承超类构造函数的属性和方法
  • 缺点:无法继承原型链上的属性和方法

原型链式继承(借用原型链实现继承)

实现

function Sub() {
this.type = "sub";
}
Sub.prototype = new Super();
var s1 = new Sub();
var s2 = new Sub();
sub1.colors.push("black");
console.log(s1.colors); //[ 'red', 'blue', 'yellow', 'black' ]
console.log(s2.colors); //[ 'red', 'blue', 'yellow', 'black' ]
sub1.say();

我们实例化了两个 Sub,在实例 s1 中为父类的 colors 属性 push 了一个颜色,但是 s2 也被跟着改变了。造成这种现象的原因就是原型链上中的原型对象它俩是共用的。这不是我们想要的,s1 和 s2 这个两个对象应该是隔离的,

组合继承

这里所谓的组合是指组合借用构造函数和原型链继承两种方式。

function Sub() {
Super.call(this);
this.type = "sub";
}
Sub.prototype = new Super();
var s1 = new Sub();
var s2 = new Sub();
s1.colors.push("black");
console.log(s1.colors); //[ 'red', 'blue', 'yellow', 'black' ]
console.log(s2.colors); //[ 'red', 'blue', 'yellow' ]

可以看到,s2和s1两个实例对象已经被隔离了,但这种方式仍有缺点。父类的构造函数被执行了两次,第一次是Sub.prototype = new Super(),第二次是在实例化的时候,这是没有必要的。那我们就继续优化吧!!

组合式继承优化1

function Sub(){
Super.call(this)
this.type = "sub";
}
Sub.prototype=Super.prototype
var s1=new Sub()
var s2=new Sub()

但是请看以下代码

console.log(s1.constructor.name);//Super

我们还可以用.constructor来观察对象是不是某个类的实例:从这里可以看到,s1的构造函数居然是父类Super,而不是子类sub,这显然不是我们想要的。

组合式继承优化2

function Sub(){
Super.call(this)
this.type = "sub";
}
Sub.prototype=Super.prototype
Sub.constructor=Sub
var s1=new Sub()
var s2=new Sub()
console.log(s1 instanceof Sub);//true
console.log(s1 instanceof Super);//true
console.log(s1.constructor.name);//Super

perfect!!

开题解答

回到开头的问题中来,

function A(){}
A.prototype.consoleA=function(){
console.log("a")
}
function B(){
A.call(this)
}
B.prototype.consoleB=function(){
console.log("b")
}
Object.assign(B.prototype,A.prototype)
function C(){
B.call(this)
}
C.prototype.consoleC=function(){
console.log("c")
}
Object.assign(C.prototype,B.prototype)

参考资料

前端面试必备之JS继承方式总结

大前端之路----JS继承的六种方式

js 中继承方式小谈的更多相关文章

  1. JS中继承方式总结

    说在前面:为了使代码更为简洁方便理解, 本文中的代码均将"非核心实现"部分的代码移出. 一.原型链方式关于原型链,可点击<深入浅出,JS原型链的工作原理>,本文不再重复 ...

  2. js各种继承方式和优缺点的介绍

    js各种继承方式和优缺点的介绍 作者: default 参考网址2 写在前面 本文讲解JavaScript各种继承方式和优缺点. 注意: 跟<JavaScript深入之创建对象>一样,更像 ...

  3. javascript中继承方式及优缺点(三)

    文以<JavaScript高级程序设计>上的内容为骨架,补充了ES6 Class的相关内容,从我认为更容易理解的角度将继承这件事叙述出来,希望大家能有所收获. 1. 继承分类 先来个整体印 ...

  4. 浅谈js中继承的理解和实现

    一.前言 java.C#等正统面向对象语言都会提供类似extend之类的处理类的继承的方法,而javascript并没有提供专门的方法用于继承,在javascript中使用继承需要一点技巧.js中实例 ...

  5. js中继承的几种用法总结(apply,call,prototype)

    一,js中对象继承 js中有三种继承方式 1.js原型(prototype)实现继承 <SPAN style="BACKGROUND-COLOR: #ffffff">& ...

  6. js中继承的方法总结(apply,call,prototype)

    一,js中对象继承 js中有三种继承方式 1.js原型(prototype)实现继承 代码如下: <SPAN style="<SPAN style="FONT-SIZE ...

  7. js各种继承方式汇总

    js中的各种继承实现汇总 首先定义一个父类: function Animal(name) { this.name = name || '动物' this.sleep = function () { c ...

  8. 谈谈JavaScript中继承方式

    聊一聊js中的继承 一.简单继承---使用原型赋值的方式继承,将实例化的对象,赋值给子级的原型 父级构造函数 function Parent(param) { this.name = 'parent' ...

  9. js的继承方式分别适合哪些应用场景?

    一.原型链 利用 Person.prototype = new Animal("Human") 实现继承: static式继承.能继承Animal.prototype.不可多重继承 ...

随机推荐

  1. utmp, wtmp - 登 录 记 录(login records)

    SYNOPSIS[总览] #include DESCRIPTION[描述] utmp 文 件 用 于 记 录 当 前 系 统 用 户 是 哪 些 人. 但 是 实 际 的 人 数 可 能 比 这 个 ...

  2. jq-demo-阻止冒泡,阻止默认行为

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. 快速失败and安全失败

    快速失败: 举个栗子: public static void main(String[] args) { ArrayList<String> list=new ArrayList<& ...

  4. 关于使用vue-router的嵌套路由的命名路由时踩的坑

    今天在做我的模仿微博项目时,我想实现点击router-link后,跳转到微博正文页面,并渲染其嵌套视图-评论组件.但是在实际实现时,我发现页面可以正常跳转,但是在页面加载后,并不渲染该页面的嵌套视图, ...

  5. C/C++ warning C4251: class ... 需要有 dll 接口由 class“..” 的客户端使用

    { 在DLL编程中, 如果调用模版类, 则可能出现类似以下的错误: 1>xclock.h(29): warning C4251: “XClock::m_FileName”: class“std: ...

  6. kafka拦截器原理|案例实操

    拦截器原理 Producer拦截器(interceptor)是在Kafka 0.10版本被引入的,主要用于实现clients端的定制化控制逻辑. 对于producer而言,interceptor使得用 ...

  7. CF601C Kleofáš and the n-thlon(期望+前缀和优化dp)

    传送门 解题思路 要求这个人的排名,我们可以先求出某个人比他排名靠前的概率,然后再乘上\(m-1\)即为答案.求某个人比他排名靠前可以用\(dp\),设\(f[i][j]\)表示前\(i\)场比赛某人 ...

  8. NX二次开发-uc1600字符串对话框

    NX9+VS2012 #include <uf.h> #include <uf_ui.h> UF_initialize(); char* cue = "输入框&quo ...

  9. Codeforces 1167C - News Distribution

    题目链接:http://codeforces.com/problemset/problem/1167/C 题意:大概就是分成几个小团体,给每个人用1 - n编号,当对某个人传播消息的时候,整个小团体就 ...

  10. 绿色版mysql 免安装使用(转载)

    MySQL绿色版的安装(mysql-5.6.22-win32.zip) Posted on 2015-01-31 23:21 卒子 阅读(10739) 评论(2) 编辑 收藏 由于工作需要最近要开始研 ...