最近在看 Node 和 ES6,感觉就是 JavaScipt 越来越像 PHP 了。好了,不扯了,直奔主题。这篇文章不是去讲 JS 原型链,而是简单聊聊 ES6 中的 Class,Node 中的 util.inherits(),ES5 中的 Object.create() 方法,及 ES6 中的 Object.setPrototypeOf() 方法。
- ES6 中引入了 Class 的概念来模拟类。
JavaScript classes introduced in ECMAScript 6 are syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax is not introducing a new object-oriented inheritance model to JavaScript. JavaScript classes provide a much simpler and clearer syntax to create objects and deal with inheritance.
以上概念直接引用自 MDN,简单讲就是 ES6 中的 Class 只不过是基于 JS 原型继承层面上的语法糖。下面是 MDN 中的一个示例:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea();
}
calcArea() {
return this.height * this.width;
}
}
const newRec = new Rectangle (10, 10);
console.log(newRec.area);
其中 class 里面的 constructor 方法会在该 class 每次实例化的时候自动执行。//和 PHP class 里面的 constructor 一样一样的。
在 class 中定义的 函数 可以省略 function 关键字。//我就稍微科普下 ES6 吧。
下面我用传统的 构造函数 来重写一下这个 Retangle 类:
function Rectangle(height, width){
this.height = height;
this.width = width;
}
Rectangle.prototype = {
get area() {
return this.calcArea();
},
calcArea: function(){
return this.height * this.width;
}
}
var newRec = new Rectangle(10,10);
console.log(newRec.area);
所以 ES6 中的 class 只不过是一种特殊的函数,如同 函数的定义有两种方式,函数声明 和 函数表达式,同样 class 的定义也有两种方式,类声明 // class foo{...} 和 类表达式 // var foo = class{...} // 继续科普 ES6,其中 函数声明和类声明的区别是,函数声明会致使声明提升, 而 类声明中则不会导致声明提升。
咦?这篇文章的题目不是 JS 继承吗?文章到现在好想一直TM在科普 ES6 的 class 啊!哈哈哈哈哈
class 之间实现继承的方式是通过使用 extends 关键字。//和 PHP一样一样的,包括 静态方法 static 的用法呀balabala...
e.g.
class Square extends Rectangle {
constructor(length){
super();
this.height = length;
this.width = length;
}
}
console.log(Square.area);
Class 之间可以通过 extends 关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。
— ECMAScript 6 入门
下面是接着之前用构造函数方法写的 Rectangle 继续写传统构造函数实现的继承:
function Square(length){
Rectangle.apply(this, [arguments[0], arguments[0]])
}
--------
*Method1//不推荐:
Square = new Rectangle();
var square = new Square(10);
console.log(Square.area);
--------
*Method2:
Square.prototype = Object.create(Rectangle.prototype)
var square = new Square(10);
console.log(Square.area);
So,
class Super {}
class Sub extends Super {}
//辣么,我们是不是可以把 ES6 中 class 的 extends 简单理解成?:
function Super(){};
function Sub(){};
Sub.prototype = Object.create(Super.prototype);
//答案是不是的
//因为 extends 实现的 class 继承 中:
console.log(Super.prototype.isPrototypeOf(Sub.prototype)) // true;
console.log(Super.isPrototypeOf(Sub)) //true;
//而 通过 Object.create() 方法实现的继承仅仅是
console.log(Super.prototype.isPrototypeOf(Sub.prototype)) //true
// class 继承的实现是://示例引用自阮老师的 《ECMAScript 6 入门》
class A {}
class B {}
//B的实例继承A的实例
Object.setPrototypeOf(B.prototype, A.prototype);
//B继承A的静态属性
Object.setPrototypeOf(B, A);
// "Object.setPrototypeOf 方法的作用与 __proto__ 相同,用来设置一个对象的 prototype对象。它是ES6正式推荐的设置原型对象的方法。"
// Object.setPrototypeOf 改方法的等同于:
function (obj, proto) {
obj.__proto__ = proto;
return obj;
}
//MDN 中的 polyfill:
Object.setPrototypeOf = Object.setPrototypeOf || function(obj, proto) { obj.__proto__ = proto; return obj; }
- Node 中使用的是 utili 这个模块里面的 inherits() 这个方法。
util.inherits(constructor, superConstructor)
Inherit the prototype methods from one constructor into another. The prototype of constructor will be set to a new object created from super Constructor.
As an additional convenience, superConstructor will be accessible through the constructor.super_ property.
上 代码:
"use strict";
const util = require('util');
function Super(){};
function Sub(){};
util.inherits(Sub, Super);
console.log(Super.prototype.isPrototypeOf(Sub.prototype)); // true;
//Buuuuuuuuuuuuut:
console.log(Super.isPrototypeOf(Sub)); // false;
Soooooooooooooo, node 文档中介绍该 util.inherits() 方法的第一句便是:
Note: usage of util.inherits() is discouraged. Please use the ES6 class and extends keywords to get language level inheritance support.
这几个概念到这里就算是草草介绍完了,总体来讲 ES6 中引入的 class ,虽然只是一种语法糖,但是它提供了一种更加简洁、清晰的语法来创建对象以及处理继承关系。