本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出 原文連接,博客地址為 http://www.cnblogs.com/jasonnode/ 。該系列課程是匯智網 整理編寫的,課程地址為 http://www.dwz.cn/3e6Yml
Class
- Class基本語法
- Class的繼承
- class的取值函數(getter)和存值函數(setter)
- Class的Generator方法
- Class的靜態方法
- new.target屬性
- 修飾器
Module
- export命令
- import命令
- 模塊的整體輸入
- module命令
- export default命令
- 模塊的繼承
Class基本語法
ES6提供了更接近傳統語言的寫法,引入了Class(類)這個概念,作為對象的模板。通過class關鍵字,可以定義類。
//定義類 class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '('+this.x+', '+this.y+')'; } }
上面代碼定義了一個“類”,可以看到里面有一個constructor方法,這就是構造方法,而this關鍵字則代表實例對象。
constructor方法
constructor方法是類的默認方法,通過new命令生成對象實例時,自動調用該方法。
實例對象
var point = new Point(2, 3);
name屬性
class Point {} Point.name // "Point"
class表達式
與函數一樣,Class也可以使用表達式的形式定義。
const MyClass = class Me { getClassName() { return Me.name; } };
Class的繼承
Class之間可以通過extends關鍵字,實現繼承。
子類會繼承父類的屬性和方法。
class Point { constructor(x, y) { this.x = x; this.y = y; } } class ColorPoint extends Point { constructor(x, y, color) { this.color = color; // ReferenceError super(x, y); this.color = color; // 正確 } }
上面代碼中,子類的constructor方法沒有調用super之前,就使用this關鍵字,結果報錯,而放在super方法之后就是正確的。
注意:ColorPoint繼承了父類Point,但是它的構造函數必須調用super方法。
下面是生成子類實例的代碼。
let cp = new ColorPoint(25, 8, 'green'); cp instanceof ColorPoint // true cp instanceof Point // true
class的取值函數(getter)和存值函數(setter)
在Class內部可以使用get和set關鍵字,對某個屬性設置存值函數和取值函數。
class MyClass { get prop() { return 'getter'; } set prop(value) { document.write('setter: '+value); } } let inst = new MyClass(); inst.prop = 123; // setter: 123 inst.prop // 'getter'
Class的Generator方法
如果某個方法之前加上星號(*),就表示該方法是一個Generator函數。
class Foo { constructor(...args) { this.args = args; } * [Symbol.iterator]() { for (let arg of this.args) { yield arg; } } } for (let x of new Foo('hello', 'world')) { document.write(x); } // hello // world
上面代碼中,Foo類的Symbol.iterator方法前有一個星號,表示該方法是一個Generator函數。Symbol.iterator方法返回一個Foo類的默認遍歷器,for...of循環會自動調用這個遍歷器。
上面代碼中,prop屬性有對應的存值函數和取值函數,因此賦值和讀取行為都被自定義了。
Class的靜態方法
類相當於實例的原型,所有在類中定義的方法,都會被實例繼承。如果在一個方法前,加上static關鍵字,就表示該方法不會被實例繼承,而是直接通過類來調用,這就稱為“靜態方法”。
class Foo { static classMethod() { return 'hello'; } } Foo.classMethod() // 'hello' var foo = new Foo(); foo.classMethod() // TypeError: undefined is not a function
上面代碼中,Foo類的classMethod方法前有static關鍵字,表明該方法是一個靜態方法,可以直接在Foo類上調用(Foo.classMethod()),而不是在Foo類的實例上調用。如果在實例上調用靜態方法,會拋出一個錯誤,表示不存在該方法。
父類的靜態方法,可以被子類繼承。
class Foo { static classMethod() { return 'hello'; } } class Bar extends Foo { } Bar.classMethod(); // 'hello'
上面代碼中,父類Foo有一個靜態方法,子類Bar可以調用這個方法。
靜態方法也是可以從super對象上調用的。
class Foo { static classMethod() { return 'hello'; } } class Bar extends Foo { static classMethod() { return super.classMethod() + ', too'; } } Bar.classMethod();
new.target屬性
new是從構造函數生成實例的命令。ES6為new命令引入了一個new.target屬性,(在構造函數中)返回new命令作用於的那個構造函數。如果構造函數不是通過new命令調用的,new.target會返回undefined,因此這個屬性可以用來確定構造函數是怎么調用的。
function Person(name) { if (new.target !== undefined) { this.name = name; } else { throw new Error('必須使用new生成實例'); } } // 另一種寫法 function Person(name) { if (new.target === Person) { this.name = name; } else { throw new Error('必須使用new生成實例'); } } var person = new Person('張三'); // 正確 var notAPerson = Person.call(person, '張三'); // 報錯
上面代碼確保構造函數只能通過new命令調用。
- Class內部調用new.target,返回當前Class。
- 子類繼承父類時,new.target會返回子類。
修飾器
修飾器(Decorator)是一個表達式,用來修改類的行為。
修飾器函數可以接受三個參數,依次是目標函數、屬性名和該屬性的描述對象。后兩個參數可省略。上面代碼中,testable函數的參數target,就是所要修飾的對象。如果希望修飾器的行為,能夠根據目標對象的不同而不同,就要在外面再封裝一層函數。
function testable(isTestable) { return function(target) { target.isTestable = isTestable; } } @testable(true) class MyTestableClass () {} document.write(MyTestableClass.isTestable) // true @testable(false) class MyClass () {} document.write(MyClass.isTestable) // false
如果想要為類的實例添加方法,可以在修飾器函數中,為目標類的prototype屬性添加方法。
function testable(target) { target.prototype.isTestable = true; } @testable class MyTestableClass () {} let obj = new MyClass(); document.write(obj.isTestable) // true
export命令
模塊功能主要由兩個命令構成:export和import。
- export命令用於用戶自定義模塊,規定對外接口;
- import命令用於輸入其他模塊提供的功能,同時創造命名空間(namespace),防止函數名沖突。
ES6允許將獨立的JS文件作為模塊,允許一個JavaScript腳本文件調用另一個腳本文件。
現有profile.js文件,保存了用戶信息。ES6將其視為一個模塊,里面用export命令對外部輸出了三個變量。
// profile.js var firstName = 'Michael'; var lastName = 'Jackson'; var year = 1958; export {firstName, lastName, year};
import命令
使用export命令定義了模塊的對外接口以后,其他JS文件就可以通過import命令加載這個模塊(文件)。
// main.js import {firstName, lastName, year} from './profile'; function sfirsetHeader(element) { element.textContent = firstName + ' ' + lastName; }
上面代碼屬於另一個文件main.js,import命令就用於加載profile.js文件,並從中輸入變量。import命令接受一個對象(用大括號表示),里面指定要從其他模塊導入的變量名。大括號里面的變量名,必須與被導入模塊(profile.js)對外接口的名稱相同。
如果想為輸入的變量重新取一個名字,import語句中要使用as關鍵字,將輸入的變量重命名。
import { lastName as surname } from './profile';
ES6支持多重加載,即所加載的模塊中又加載其他模塊。
模塊的整體輸入
export命令除了輸出變量,還可以輸出方法或類(class)。下面是一個circle.js文件,它輸出兩個方法area和circumference。
// circle.js export function area(radius) { return Math.PI * radius * radius; } export function circumference(radius) { return 2 * Math.PI * radius; }
然后,main.js輸入circlek.js模塊。
// main.js import { area, circumference } from 'circle'; document.write("圓面積:" + area(4)); document.write("圓周長:" + circumference(14));
上面寫法是逐一指定要輸入的方法。另一種寫法是整體輸入。
import * as circle from 'circle'; document.write("圓面積:" + circle.area(4)); document.write("圓周長:" + circle.circumference(14));
module命令
module命令可以取代import語句,達到整體輸入模塊的作用。
// main.js module circle from 'circle'; document.write("圓面積:" + circle.area(4)); document.write("圓周長:" + circle.circumference(14));
module命令后面跟一個變量,表示輸入的模塊定義在該變量上。
export default命令
為加載模塊指定默認輸出,使用export default命令。
// export-default.js export default function () { document.write('foo'); }
上面代碼是一個模塊文件export-default.js,它的默認輸出是一個函數。
其他模塊加載該模塊時,import命令可以為該匿名函數指定任意名字。
// import-default.js import customName from './export-default'; customName(); // 'foo'
上面代碼的import命令,可以用任意名稱指向export-default.js輸出的方法。需要注意的是,這時import命令后面,不使用大括號。
模塊的繼承
模塊之間也可以繼承。
假設有一個circleplus模塊,繼承了circle模塊。
// circleplus.js export * from 'circle'; export var e = 2.71828182846; export default function(x) { return Math.exp(x); }
上面代碼中的“export *”,表示輸出circle模塊的所有屬性和方法,export default命令定義模塊的默認方法。
這時,也可以將circle的屬性或方法,改名后再輸出。
// circleplus.js export { area as circleArea } from 'circle';
上面代碼表示,只輸出circle模塊的area方法,且將其改名為circleArea。
加載上面模塊的寫法如下。
// main.js module math from "circleplus"; import exp from "circleplus"; document.write(exp(math.pi));
上面代碼中的"import exp"表示,將circleplus模塊的默認方法加載為exp方法。