美文网首页
如何用ES5语法实现继承

如何用ES5语法实现继承

作者: 卡拉咖啦 | 来源:发表于2019-08-21 20:23 被阅读0次

JS 提供了创建类的语法糖 “class”,以及用与创建子类的关键字 “extends”,那么,问题来了,如果我们不用这些语法糖,我们应该如何实现 JS 中的原型继承呢?

原型链是个什么链

这是我们知道的:

值.proto === 值的构造函数.prototype
这句话的意思是,每个值都有一个隐藏的 proto 属性绑定它的构造函数的 prototype 属性
如果是一个数组,那么
[].proto === Array.prototype
从这个式子表达了一个数组是如何继承数组的原型属性的,而,进一步,数组作为对象的那一部分是怎么继承下来的呢?
答案是:
Array.prototype.proto === Object.prototype

绑定 Object.prototype 的是 Array 构造函数的 prototype 属性。

于是,所谓的“原型链”,本质上就是多个 prototype 串起来的链。

prototype 是个什么东西?

prototype 这个东西,当我们声明一个函数的时候,这个函数就自带一个 prototype 属性,而对象是没有默认的 prototype 属性的(这也是为什么我们说,对象没法被继承,如果还是想继承,需要用到 Object.setPrototypeOf 属性)

继承.png

在没有 class 之前,我们是这么给构造函数写原型属性的:

fn.prototype.a = function(){}

当我们这么写的时候,实际上就意味着,prototype 是一个对象,

于是,所谓的“原型链”,更本质上就是串起来的对象。

proto 与 prototype

当然,仅仅把对象串起来,并不能自动实现“继承”,在整个继承中的关键,其实是“proto”,也就是说,通过 __proto__ 把连起来的对象串,自带“继承”的特效~

到了这里,我们不得不严格区分一下 proto 与 prototype

__proto__怎么看都是 prototype 的缩写,而且 值.__proto__ === 构造函数.prototype 不是说明他们完全等同吗?

但他们确实不是一回事,比如:
1.如果我们不主动设置的话,对象并没有 prototype 属性,但是对象天生就有 proto;
2.我们可以把 __proto__ 理解为有继承的作用,但是 prototype 没有;
3.也就是说,__proto__ 更偏向于表达“绑定、继承”这些动作,而 prototype 表示,被绑定被继承的那堆东西。

进而,如何绑定 __proto__ ? JS 不允许我们手动设置 __proto__
对于我们来说,实现一个有继承效果的 __proto__ 就是使用 new, 别忘了,new 的作用之一就是把新生成的对象 proto 属性绑定原型

构造函数怎么办?

说了半天,我们还没有提构造函数,我们可以这么认为,上面说讲的内容就是构建一个对象的内在关系,而构造函数所要做的就是让我们的对象“实体化” —— 它就是用来产生对象的。

当我们 new 一个构造函数的时候,就会产生一个新的空对象,并把这个对象作为 this 把构造函数执行一遍。

class A {
  constructor(){
    this.x = 1
    console.log("aaa")
  }
}

class B extends A {
  constructor() {
    super()
    this.y = 2
    console.log("bbb")
  }
}

let c = new B
//→ aaa
//→ bbb

console.log(c) //→ {x: 1, y: 2}

看上面的代码,我们发现,子类用于创建对象的时候,不仅子构造函数会执行,父类的构造函数也会执行。

到底我们该怎么做?

于是,如果我们想实现“继承”,应该如何做?关键点在于:
1.子构造函数要调用父构造函数;
2.用 new 实现原型链的继承;

// B 继承 A

function A (){
  this.a = "a"
}
A.prototype.fa = function(){console.log("fa")}

function B(){
  A.apply(this, arguments) // 调用 A 构造函数
  this.b = "b"
}

let f = function(){}
f.prototype = A.prototype
B.prototype = new fn() // 通过 new, B.prototype 就变成了一个有 __proto__ 属性指向 A.prototype 的空对象

B.prototype.fb = function(){console.log("fb")} // 设置其它属性 ……

相关文章

  • 如何用es5实现继承

    extend (继承) 如何用 es5 实现继承 测试 结果 原文链接

  • 如何用ES5语法实现继承

    JS 提供了创建类的语法糖 “class”,以及用与创建子类的关键字 “extends”,那么,问题来了,如果我们...

  • JS 继承的两种写法

    ES5 ES6 两种方法都能实现继承,本质上ES6继承是ES5继承的语法糖,会更简单些,但是假如要添加一个非函数的...

  • 继承:es5 vs es6

    es5如何实现继承 es5实现继承主要是通过原型来实现的 首先实现一个父类 function Father(na...

  • ES5和ES6中继承的不同之处

    ES5和ES6中继承的不同之处 1、JS中视没有继承的,不过可以通过构造函数或是原型等实现继承,ES5实现继承的方...

  • 前端常见面试题(八)@郝晨光

    ES5/ES6 的继承除了写法以外还有什么区别? ES5寄生组合式继承(只是列举一个方法,ES5继承还有很多实现方...

  • 用ES5和ES6实现继承

    ES5 prototype实现继承 ES6 写法

  • ES6中的class与继承

    class是创建类对象与实现类继承的语法糖,旨在让ES5中对象原型的写法更加清晰,易读。 基本使用: clas...

  • Class 的继承 extend继承 es6继承基本用法

    Class继承基本用法 Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,...

  • ES6学习笔记—Class基本语法

    1、引言 JavaScript是一门基于原型继承的语法,ES5中我们实现面向对象构造“父类”的写法一般通过构造函数...

网友评论

      本文标题:如何用ES5语法实现继承

      本文链接:https://www.haomeiwen.com/subject/jefwsctx.html