這篇文章主要介紹JavaScript中的屬性描述符、ES6中的module、箭頭函數。javascript
1、對象的屬性
屬性描述符: 對象裏目前存在的屬性描述符有兩種主要形式:數據描述符和存取描述符。數據描述符是一個具備值的屬性,該值多是可寫的,也可能不是可寫的。存取描述符是由getter-setter函數對描述的屬性。描述符必須是這兩種形式之一,不能同時是二者。
數據描述符(數據屬性)和存取描述符(訪問器屬性)均具備的可選鍵值:
configurable: 當且僅當該屬性的 configurable 爲 true 時,該屬性能從對應的對象上被刪除,以及除value和writable特性外的其餘特性是否能夠被修改。默認爲 false。
enumerable: 當且僅當該屬性的enumerable爲true時,該屬性纔可以出如今對象的枚舉屬性中。默認爲 false。
數據描述符(數據屬性)的可選鍵值:
value: 該屬性對應的值。能夠是任何有效的 JavaScript 值(數值,對象,函數等)。默認爲 undefined。
writable: 當且僅當該屬性的writable爲true時,value才能被賦值運算符改變。默認爲 false。
存取描述符(訪問器屬性)的可選鍵值:
get: 一個給屬性提供 getter 的方法,若是沒有 getter 則爲 undefined。當訪問該屬性時,該方法會被執行,方法執行時沒有參數傳入,可是會傳入this對象(因爲繼承關係,這裏的this並不必定是定義該屬性的對象)。默認爲 undefined。
set: 一個給屬性提供 setter 的方法,若是沒有 setter 則爲 undefined。當屬性值修改時,觸發執行該方法。該方法將接受惟一參數,即該屬性新的參數值。默認爲 undefined。
注: 若是一個描述符不具備value,writable,get 和 set 任意一個關鍵字,那麼它將被認爲是一個數據描述符。若是一個描述符同時有(value或writable)和(get或set)關鍵字,將會產生一個異常。html
2、設置、修改對象單個屬性的描述
Object.defineProperty(): 該方法會直接在對象上定義一個新屬性,或者修改一個對象的現有屬性,並返回這個對象。IE8部分支持。
Object.defineProperty()的語法:
Object.defineProperty(obj, prop, descriptor)
obj: 要在其上定義屬性的對象。
prop: 要定義或修改的屬性的名稱。
descriptor: 將被定義或修改的屬性描述符。java
Object.defineProperty(obj, 'val', { value: 1, writable: false, enumerable: true, configurable: true }) obj.val = 2; console.log(obj.val); // 1 Object.defineProperty(obj, 'val', { value: 1, writable: true, enumerable: true, configurable: true }) obj.val = 3; console.log(obj.val); // 3 Object.defineProperty(obj1, 'val', { get() { num += 1; return num; }, set(newVal) { num = newVal; }, enumerable: true, configurable: true }) console.log(obj1.val); // 2 console.log(obj1.val); // 3
屬性的賦值器(setter)和取值器(getter): 利用ES6屬性的簡潔表示法,使用get和set關鍵字來建立訪問器屬性。es6
const obj = { num: 1, get num1() { return this.num; }, set num1(newVal) { this.num += 1; } }
3、設置、修改對象多個屬性的描述
Object.defineProperties(): 直接在一個對象上定義新的屬性或修改現有屬性,並返回該對象。
Object.defineProperties()語法: Object.defineProperties(obj, props) / Object.defineProperties(obj, {property: descriptor, property: descriptor})
obj: 在其上定義或修改屬性的對象。
property: 要定義或修改的屬性的名稱。
descriptor: 將被定義或修改的屬性描述符。瀏覽器
var obj = {}; Object.defineProperties(obj, { 'property1': { value: true, writable: true }, 'property2': { value: 'Hello', writable: false } });
4、獲取對象屬性描述
Object.getOwnPropertyDescriptor(): 返回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不須要從原型鏈上進行查找的屬性)。IE8支持。
Object.getOwnPropertyDescriptor()的語法:
Object.getOwnPropertyDescriptor(obj, prop)
obj: 須要查找的目標對象
prop: 目標對象內屬性名稱服務器
let obj = {}, obj1 = {}; Object.defineProperty(obj, 'num', { value: 1 }) obj1.num = 1; console.log(Object.getOwnPropertyDescriptor(obj, 'num')); // {value: 1, writable: false, enumerable: false, configurable: false} console.log(Object.getOwnPropertyDescriptor(obj, 'num')); // {value: 1, writable: true, enumerable: true, configurable: true}
參考來自:
MDN--Object.defineProperty()
MDN--Object.defineProperties()
MDN--Object.getOwnPropertyDescriptor()app
1、module的定義
模塊功能主要由兩個命令構成:export和import。export命令用於規定模塊的對外接口,import命令用於輸入其餘模塊提供的功能。異步
2、export命令
1) 定義: 一個模塊就是一個獨立的文件,改文件內部的全部變量,外部沒法獲取,只有經過export關鍵字輸出該變量、函數或類,外部纔可以讀取該變量、函數或類。
2) 注意點:
a、export命令規定的是對外的接口,必須與模塊內部的變量創建一一對應的關係,因此不能經過export直接輸出一個變量或值
b、export命令必須處於模塊頂層,不能處於塊級做用域內,import也是如此。這是由於處於條件代碼塊之中,就沒有辦法作靜態優化了,違背了ES6模塊的設計初衷
使用方法:async
// 輸出一 export var a = 1; // 輸出二 var b = 1; var c = 2; export { b, c }; // 錯誤寫法,由於沒有提供對外的接口 var d = 3; export d; export 1;
3、export default命令
1) 定義: 爲模塊指定默認輸出,在輸入時無需知道原模塊輸出的變量名,能夠用任意名稱來指向該模塊輸出的內容
2) 注意點:
a、export命令用於指定模塊的默認輸出,一個模塊只能有一個默認輸出,所以export default命令只能使用一次,否則會報錯
b、本質上export default就是輸出一個叫作default的變量或方法,而後系統容許你爲它取任意名字。它後面不能跟變量聲明語句
使用方法:函數
// 輸出一個變量 var a = 1; export defualt a; // 輸出一個值 export default 1; // 輸出一個方法 export default funciton () { } // 輸出一個方法 function add() {} export default add; // 輸出一個對象 export default { }
4、import命令
1) 定義: 使用export命令定義了模塊的對外接口之後,其餘 JS 文件就能夠經過import命令加載這個模塊
2) 注意點:
a、加載export輸出的變量、函數、類時,須要使用import命令接受一對大括號,裏面指定要從其餘模塊導入的變量名,大括號裏的變量名,必須與被導入模塊對外接口的名稱同樣(import {variable} from './index.js'
);加載export default輸出的變量、函數、類時,可使用任意名稱指向輸出的方法,import後面不使用大括號(import allFn from '/index.js'
)
b、加載模塊全部的輸出值,利用星號(*)指定一個對象,全部輸出值都加載在這個對象上面,包括export default
c、import命令輸入的變量都是隻讀的,不容許在加載模塊的裏面改寫接口。只有當輸出的是一個對象時,能夠改寫其屬性
d、import命令具備提高效果,會提高到整個模塊的頭部,首先執行。import命令是編譯階段執行的,在代碼運行以前
e、若是屢次重複執行同義句import語句,那麼只會執行一次,而不會執行屢次。當屢次使用import引入同一個module的不一樣方法時,引入的方法對應的都是一個module,import語句是單例模式
f、import是靜態執行的,因此不能使用表達式、變量、條件語句、代碼塊
g、import輸入時,語法要求不帶as的默認值(export default輸出的)永遠在最前
使用方法:
// 執行所加載的模塊,引用它的模塊沒法獲取它的任何信息 import 'lodash'; // 加載export輸出的變量 import { firstName } from './index.js'; // 加載export default輸出的變量 import allFn from './index.js'; // 在一條import語句中同時輸入默認方法和其餘接口 import _, { each } from './lodash'; // 加載模塊全部的輸出值,利用星號(*)指定一個對象,全部輸出值都加載在這個對象上面 import * as circle from './index.js'; // 單例的表現 // test1.js var a = 1; export function add() { a++; console.log(a); } // test2.js export { add } from './text1.js'; // index.html import { add } from './test.js'; import { add as getCount } from './test1.js'; add(); // 2 getCount(); // 3
5、as關鍵字:
1) 定義: 使用as關鍵字能夠爲輸出或輸入的變量從新命名
2) 注意點: as關鍵字的前面表示原本的名字,後面的是新名字(oldName as newName)
使用方法:
// 輸出時重命名 var a = 1, b = 2; export { a as num1, b as num2 } // 輸入時重命名 import * as numModule from './index.js'; // 輸入時重命名 import {x as num1} from './index.js'
6、export和import的複合用法
1) 定義: 在一個模塊中,先輸入後輸出同一個模塊,import語句能夠和export語句寫在一塊兒
2) 注意點:
a. export和import寫成一行時,接口其實沒有被導入當前模塊,只是至關於對外轉發了這個接口,當前模塊不能直接使用該接口
b. 在export和import複合使用時,* 表明的是所有的其餘接口(export輸出的),不包含默認接口(export default輸出的)
使用方法:
// 使用一 // 先輸入後輸出其餘接口(export輸出的),該模塊中沒法使用foo、bar export { foo, bar } from './index.js'; // 別的模塊中使用 import { foo, bar } from './util.js'; // 使用二 // 總體輸出其餘接口(export輸出的) export * from './index.js'; // 別的模塊中使用 import * as all from './util.js'; // 使用三 // 先輸入後輸出默認接口(export default輸出的),該模塊中沒法使用該方法 export { default } from './index.js'; // 別的模塊中使用 import allFn from './util.js';
7、跨模塊使用
定義: 是一個模塊裏的接口跨多個文件使用
使用方法:
// test1.js export const A = 1; // test2.js export const B = 2; // 合併全部的接口在index.js中 export { A } from './test1.js'; export { B } from './test2.js';
8、ES6模塊的好處
1) ES6模塊能夠按需加載。在加載時,只加載import命令輸入的方法和變量,模塊中其餘方法和變量不加載。這種加載稱爲"編譯時加載"或者靜態加載,即ES6能夠在編譯時就完成模塊加載。而CommonJS和AMD模塊,只能在運行時肯定模塊的的依賴關係、輸入輸出變量,是"運行時加載",由於只有運行時才能獲得這個對象。好比CommonJS模塊加載時,實質上是總體加載,生成一個對象,再從對象上讀取加載的方法。
2) 再也不須要UMD模塊格式了,未來服務器和瀏覽器都會支持 ES6 模塊格式。目前,經過各類工具庫,其實已經作到了這一點。
3) 未來瀏覽器的新 API 就能用模塊格式提供,再也不必須作成全局變量或者navigator對象的屬性。
) 再也不須要對象做爲命名空間(好比Math對象),將來這些功能能夠經過模塊提供。
9、ES6模塊注意點
ES6的模塊自動採用嚴格模式,關於嚴格模塊一般須要注意的就兩點,一是變量必須聲明後再使用,二是頂層的this指向undefined。
10、腳本和模塊的區別
腳本的特色:
1) 是JavaScript源文件的一種
2) 經過<script type="application/javascript">標籤的src屬性,引入外部js文件
3) 在沒有src屬性時能夠直接在<script type="application/javascript">標籤內部寫代碼。因爲瀏覽器腳本的默認語言是 JavaScript,所以type="application/javascript"能夠省略
4) 兼容性好,沒法在其中使用export和import
5) 腳本默認是同步加載的,能夠在<script>上添加async(腳本一旦下完,渲染引擎就會中斷渲染,執行這個腳本以後,再渲染)、defer(該腳本要等到整個頁面在內存中正常渲染結束,也就是DOM結構徹底生成,以及其餘腳本執行完成後纔會執行)屬性來讓其異步加載
模塊的特色:
1) 是JavaScript源文件的一種
2) 瀏覽器對於type="module"的<script>都是異步加載的,不會形成阻塞瀏覽器,即等到整個頁面渲染完,再執行模塊腳本,等同於打開了<script>標籤的defer屬性,若是有多個<script type="module">,會按照在頁面出現的順序依次執行。也能夠本身在<script>設置async屬性,這時只要加載完成,渲染引擎就會中斷渲染當即執行,執行完成後再恢復渲染。一旦使用了async屬性,<script type="module">就不會按照在頁面出現的順序執行,而是隻要該模塊加載完成,就執行該模塊
3) 經過<script type="module">標籤的src屬性引入外部模塊,執行所加載的模塊,引用它的模塊沒法獲取它的任何信息
4) 在沒有src屬性時,在<script type="module"></script>中間能夠內嵌到網頁中,語法行爲與加載外部腳本徹底一致。能夠在其中使用import、export、export default命令
5) 兼容性很差,IE不支持,Edge16支持
參考:
ES6阮一峯--Module 的語法
ES6阮一峯--Module 的加載實現
1、箭頭函數的特色
1) 函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。this指向的固定化,並非由於箭頭函數內部有綁定this的機制,實際緣由是箭頭函數根本沒有本身的this,致使內部的this就是外層代碼塊的this(也就是this的指向向上提一級)。正是由於它沒有this,因此也就不能用做構造函數。
2) 不能夠看成構造函數,也就是說,不可使用new命令,不然會拋出一個錯誤。
3) 不可使用arguments對象,該對象在函數體內不存在。若是要用,能夠用 rest 參數代替。
4) 不可使用yield命令,所以箭頭函數不能用做 Generator 函數。
5) 箭頭函數沒有本身的this,因此不能使用call()、apply()、bind()方法去改變this的指向
6) 箭頭函數中沒有arguments、super、new.target,它們指向外層函數的對應變量。
2、箭頭函數轉換成ES5的代碼
// ES6 function foo() { setTimeout( () => { console.log({'id', this.id}); }, 100) } // ES5 function foo() { var _this = this; setTimeout( function () { console.log('id', _this.id); }, 100) }
來源: 阮一峯ES6入門--箭頭函數
以上內容若有不對,但願你們指出,謝謝。