blog tumbnail

JS 里的继承

什么是继承

首先我们得了解什么是继承,根据维基百科我们可以知道,在计算机语言里的继承是一个概念,指的是如果一个类别 B 继承自另外一个类别 A ,就把这个 B 称为 A 的子类,A 为 B 的父类,或者 A 为 B 的超类。继承可以使 B 继承 A 的所有属性方法,而不用再写一遍。B 在继承 A 属性的同时,也可以重新定义某些属性,并重写某些方法。这样会覆盖原来的属性方法,当然也可以扩展增加新属性和方法。对静态语言来说,继承属于静态的, 在编译期就已决定,无法在运行期扩展。

对与 JavaScript 来说,JS 是动态的,而且也没有提供 class 的实现(ES6 引入了 class 关键字,但也只是语法糖,JavaScript 仍是基于原型继承的)。

JS里的继承是怎么回事

JS 里面只有一种结构:对象。对于对象来说,每个实例对象都有一个私有的属性(称为 __proto__)指向它的构造函数的原型对象(prototype),可以说实例对象都是继承某个原型对象。而每一个原型对象也有一个自己的原型对象,层层向上,最终指向 null 。而根据定义,null 是没有原型的,所以每条原型链的终点就是 null。也就是说,每个对象都是一层一层继承过来。 1

像上图就显示了字符串的原型是 String 的构造函数。

如果用 A 构造 B 的话,B 便继承了 A 的所有属性,当访问 B 的属性时,如果没有读取到,便会一直往原型链读取。

2

像上图,先声明一个构造函数 a ,然后构造实例 b 和 c 。其中 b 写入属性 q 与 w ,c 没有写入。可以看出 b 写入的属性覆盖了原型的属性,而 c 则没有,所以访问 c 的 q 属性时,读取是原型里的值。

JS的四种继承方法

使用语法结构创建

也就是使用 JS 中内置的构造函数,来自 MDN 的例子

var o = {a: 1}; // o 这个对象继承了 Object.prototype 上面的所有属性 // o 自身没有名为 hasOwnProperty 的属性 // hasOwnProperty 是 Object.prototype 的属性 // 因此 o 继承了 Object.prototype 的 hasOwnProperty // Object.prototype 的原型为 null // 原型链如下: // o ---> Object.prototype ---> null var a = ["yo", "whadup", "?"]; // 数组都继承于 Array.prototype // (Array.prototype 中包含 indexOf, forEach 等方法) // 原型链如下: // a ---> Array.prototype ---> Object.prototype ---> null function f(){ return 2; } // 函数都继承于 Function.prototype // (Function.prototype 中包含 call, bind等方法) // 原型链如下: // f ---> Function.prototype ---> Object.prototype ---> null

使用构造器创建对象来进行继承

在 JS 中, 构造器其实就是一个普通的函数,当使用 new 操作符来作用这个函数时,它就可以称为构造函数。(new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。)如下图所示: 3

function Graph() { this.vertices = []; this.edges = []; } Graph.prototype = { addVertex: function(v){ this.vertices.push(v); } }; var g = new Graph(); // g 是生成的对象,他的自身属性有 'vertices' 和 'edges'。 // 在 g 被实例化时,g.[[Prototype]] 指向了 Graph.prototype。

使用Object.create创建的对象来进行继承

Object.create() 是 ES5 中新增加的一个方法,可以用来创建新的对象。 新对象的原型就是调用 creat 传递的第一个参数。

var a = {a: 1}; // a ---> Object.prototype ---> null var b = Object.create(a); // b ---> a ---> Object.prototype ---> null console.log(b.a); // 1 (继承而来) var c = Object.create(b); // c ---> b ---> a ---> Object.prototype ---> null var d = Object.create(null); // d ---> null console.log(d.hasOwnProperty); // undefined, 因为d没有继承Object.prototype

使用class关键字创建对象

ES 6 引入了一套新的关键词来实现 class。这些关键词包括 class、constructor、static、extends 和 super。作用与 java 里的差不多,不过 js 仍是基于原型的继承。

"use strict"; class Polygon { constructor(height, width) { this.height = height; this.width = width; } } class Square extends Polygon { constructor(sideLength) { super(sideLength, sideLength); } get area() { return this.height * this.width; } set sideLength(newLength) { this.height = newLength; this.width = newLength; } } var square = new Square(2);

继承在业务代码中的实际应用

继承在业务代码中应用很广泛,无论是扩展方法,还是编写工具组件都有所应用。