1. 程式人生 > 其它 >Vue進階(二十一):vue開發之es6知識儲備

Vue進階(二十一):vue開發之es6知識儲備

尊重原創版權: https://www.gewuweb.com/hot/9409.html

Vue進階(二十一):vue開發之es6知識儲備

1、 let 所宣告的變數,只在 let 命令所在的程式碼塊內有效。

2、不存在變數提升:所宣告的變數一定要在聲明後使用,否則報錯。

一定要先宣告,再去使用。 let x=x; 這樣就是錯誤的。

ES6明確規定,如果區塊中存在let和const命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域。凡是在宣告之前就使用這些變數,就會報錯。

3、不允許重複宣告: let 不允許在相同作用域內,重複宣告同一個變數。即不能在函式內部重新宣告引數。

塊級作用域

1、為什麼需要塊級作用域?

ES5 只有 全域性作用域函式作用域 ,沒有 塊級作用域 ,這帶來很多不合理的場景。

第一種場景,內層變數可能會覆蓋外層變數。

var tmp = new Date();
function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';
  }
}
f(); // undefined

第二種場景,用來計數的迴圈變數洩露為全域性變數。下面程式碼中,變數i只用來控制迴圈,但是迴圈結束後,它並沒有消失,洩露成了全域性變數。

var s = 'hello';
for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}
console.log(i); // 5

2、 ES6 的塊級作用域:外層作用域無法讀取內層作用域的變數。內層作用域可以定義外層作用域的同名變數。

下面的函式有兩個程式碼塊,都聲明瞭變數n,執行後輸出5。這表示外層程式碼塊不受內層程式碼塊的影響。如果兩次都使用var定義變數n,最後輸出的值才是10。

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
    console.log(n);
  }
  console.log(n); // 5
}
f1()

塊級作用域的出現,實際上使得獲得廣泛應用的立即執行函式表示式( IIFE )不再必要了。

// IIFE 寫法
(function () {
  var tmp = ...;
  ...
}());
// 塊級作用域寫法
{
  let tmp = …;
  …
}

塊級作用域用法:考慮到環境導致的行為差異太大,應該避免在塊級作用域內宣告函式。如果確實需要,也應該寫成 函式表示式 ,而不是 函式宣告語句

// 函式宣告語句
{
  let a = 'secret';
  function f() {
    return a;
  }
}
// 函式表示式
{
  let a = ‘secret’;
  let f = function () {
  return a;
};
}

ES6 的塊級作用域允許宣告函式的規則,只在使用大括號的情況下成立,如果沒有使用大括號,就會報錯。

3、do 表示式

本質上,塊級作用域是一個語句,將多個操作封裝在一起,沒有返回值。存在返回值的辦法就是在塊級作用域之前加上 do ,使它變為 do
表示式,然後就會返回內部最後執行的表示式的值。

let x = do {
  let t = f();
  t * t + 1;
};

const 命令

const 宣告一個只讀的常量。一旦宣告,常量的值就不能改變。 const 一旦宣告變數,就必須立即初始化,不能留到以後賦值。

const 的作用域與 let 命令相同:只在宣告所在的塊級作用域內有效。

const 命令宣告的常量也是不提升,同樣存在暫時性死區,只能在宣告的位置後面使用。

const 宣告的常量,也與 let 一樣不可重複宣告。

箭頭函式

1、省略了 function ,花括號‘ {} ’用‘ => ’代替,這種寫法更簡潔。

2、優點:函式體內的 this 指向始終是定義它所在的物件,而不會指向呼叫它的物件,我們知道 es5 中的函式是誰執行它,它就指向誰。

Promise 物件

一、 Promise 是 非同步程式設計 的一種解決方案,比傳統的解決方案—— 回撥函式和事件 ——更合理和更強大。 Promise
物件是一個建構函式,用來生成 Promise 例項.

與 ‘ new ’ 運算子一起使用建立物件並初始化物件的‘函式’就是建構函式;
例項化(在面向物件的程式設計中,通常把用類建立物件的過程稱為例項化。)物件就是建立物件的過程!

var request = new XMLHttpRequest();

“ new XMLHttpRequest(); ” 這句話就是一個標準的建構函式!我們 “var” 聲明瞭一個 “request” 物件,用建構函式 “
new XMLHttpRequest(); ” 來初始化這個 “request” 物件為它賦初始值。

所謂 Promise ,簡單說就是一個容器,裡面儲存著某個未來才會結束的事件(通常是一個非同步操作)的結果。從語法上說, Promise
是一個物件,從它可以獲取非同步操作的訊息。 Promise 提供統一的 API ,各種非同步操作都可以用同樣的方法進行處理。

二、 Promise 物件有以下兩個特點:

  1. 物件的狀態不受外界影響。 Promise 物件代表一個非同步操作,有三種狀態: pending (進行中)、 fulfilled (已成功)和 rejected (已失敗)。只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
  2. 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。 Promise 物件的狀態改變,只有兩種可能:從 pending 變為 fulfilled 和從 pending 變為 rejected 。只要這兩種情況發生,狀態就凝固了,不會再變,會一直保持這個結果,這時就稱為 resolved (已定型)。如果改變已經發生,再對 Promise 物件添加回調函式,也會立即得到這個結果。這與事件( Event )完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。

同時, Promise 物件也有缺點:

  1. 無法取消 Promise ,一旦新建它就會立即執行,無法中途取消。
  2. 如果不設定回撥函式, Promise 內部丟擲的錯誤,不會反應到外部。
  3. 當處於 pending 狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。

下面程式碼創造了一個 Promise 例項。

var promise = new Promise(function(resolve, reject) {
  // ... some code
if (/ 非同步操作成功 /){
	resolve(value);
} else {
	reject(error);
}
});

Promise 建構函式接受一個函式作為引數,該函式的兩個引數分別是 resolve 和 reject 。它們是兩個函式,由
JavaScript 引擎提供,不用自己部署。

Promise 例項生成以後,可以用 then 方法分別指定 resolved 狀態和 rejected 狀態的回撥函式。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

下面是一個 Promise 物件的簡單例子。

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}
timeout(100).then((value) => {
	console.log(value);
});

上面程式碼中, timeout 方法返回一個 Promise 例項,表示一段時間以後才會發生的結果。過了指定的時間(ms引數)以後, Promise
例項的狀態變為 resolved ,就會觸發 then 方法繫結的回撥函式。一般情況不呼叫 setTimeout 指定時間, Promise
新建後就會立即執行。

三、Promise.prototype.then()

then 方法返回的是一個新的 Promise 例項(注意,不是原來那個 Promise 例項)。因此可以採用鏈式寫法,即 then
方法後面再呼叫另一個 then 方法。

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function funcA(comments) {
  console.log("resolved: ", comments);
}, function funcB(err){
  console.log("rejected: ", err);
});

上面程式碼中,第一個 then 方法指定的回撥函式,返回的是另一個 Promise 物件。這時,第二個then 方法
指定的回撥函式,就會等待這個新的 Promise 物件狀態發生變化。如果變為 resolved ,就呼叫 funcA ,如果狀態變為
rejected ,就呼叫 funcB 。如果採用箭頭函式,上面的程式碼可以寫得更簡潔。

getJSON("/post/1.json").then(
  post => getJSON(post.commentURL)
).then(
  comments => console.log("resolved: ", comments),
  err => console.log("rejected: ", err)
);

四、Promise.prototype.catch()

Promise.prototype.catch 方法是 .then(null, rejection) 的別名,用於指定發生錯誤時的回撥函式。

getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {
  // 處理 getJSON 和 前一個回撥函式執行時發生的錯誤
  console.log('發生錯誤!', error);
});

上面程式碼中,getJSON方法返回一個 Promise 物件,如果該物件狀態變為 resolved ,則會呼叫 then
方法指定的回撥函式;如果非同步操作丟擲錯誤,狀態就會變為 rejected ,就會呼叫 catch 方法指定的回撥函式,處理這個錯誤。另外,
then 方法指定的回撥函式,如果執行中丟擲錯誤,也會被 catch 方法捕獲。

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 處理前面三個Promise產生的錯誤
});

Promise 物件的錯誤具有“冒泡”性質,會一直向後傳遞,直到被捕獲為止。也就是說,錯誤總是會被下一個 catch 語句捕獲。

一般來說,不要在 then 方法裡面定義 Reject 狀態的回撥函式(即 then 的第二個引數),總是使用 catch 方法。

// bad
promise
  .then(function(data) {
    // success
  }, function(err) {
    // error
  });
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});

上面程式碼中,第二種寫法要好於第一種寫法,理由是第二種寫法可以捕獲前面 then 方法執行中的錯誤,也更接近同步的寫法( try/catch
)。因此,建議總是使用 catch 方法,而不使用 then 方法的第二個引數。

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    // 下面一行會報錯,因為x沒有宣告
    resolve(x + 2);
  });
};
someAsyncThing().then(function() {
	console.log(‘everything is great’);
});
setTimeout(() => { console.log(123) }, 2000);
// Uncaught (in promise) ReferenceError: x is not defined
// 123

上面程式碼中, someAsyncThing 函式產生的 Promise 物件,內部有語法錯誤。瀏覽器執行到這一行,會打印出錯誤提示
ReferenceError: x is not defined ,但是不會退出程序、終止指令碼執行,2秒之後還是會輸出123。這就是說, Promise
內部的錯誤不會影響到 Promise 外部的程式碼,通俗的說法就是“ Promise 會吃掉錯誤 ”。

一般總是建議, Promise 物件後面要跟 catch 方法,這樣可以處理 Promise 內部發生的錯誤。 catch
方法返回的還是一個 Promise 物件,因此後面還可以接著呼叫 then 方法。

五、Promise.all()

Promise.all 方法用於將多個 Promise 例項,包裝成一個新的 Promise 例項。

   var p = Promise.all([p1, p2, p3]); 

Promise.all 方法接受一個數組作為引數,p1、p2、p3都是 Promise 例項,如果不是,就會先呼叫下面講到的
Promise.resolve 方法,將引數轉為 Promise 例項,再進一步處理。

p的狀態由p1、p2、p3決定,分成兩種情況:

(1)只有p1、p2、p3的狀態都變成 fulfilled ,p的狀態才會變成 fulfilled
,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回撥函式。

(2)只要p1、p2、p3之中有一個被 rejected ,p的狀態就變成 rejected ,此時第一個被 reject
的例項的返回值,會傳遞給p的回撥函式。

六、Promise.race()

Promise.race 方法同樣是將多個 Promise 例項,包裝成一個新的 Promise 例項。

var p = Promise.race([p1, p2, p3]);
上面程式碼中,只要p1、p2、p3之中有一個例項率先改變狀態,p的狀態就跟著改變。那個率先改變的 Promise 例項的返回值,就傳遞給p的回撥函式。

七、Promise.resolve()

有時需要將現有物件轉為 Promise 物件, Promise.resolve 方法就起到這個作用。

八、模組語法

1、 ES6 在語言標準的層面上,實現了模組功能,而且實現得相當簡單,完全可以取代 CommonJS 和 AMD
規範,成為瀏覽器和伺服器通用的模組解決方案。

ES6 模組不是物件,而是通過 export 命令顯式指定輸出的程式碼,再通過 import 命令輸入。

// ES6模組
import { stat, exists, readFile } from 'fs';

上面程式碼的實質是從fs模組載入3個方法,其他方法不載入。這種載入稱為“ 編譯時載入 ”或者 靜態載入 ,即 ES6
可以在編譯時就完成模組載入,效率要比 CommonJS 模組的載入方式高。

2、嚴格模式

  1. 變數必須聲明後再使用;
  2. 函式的引數不能有同名屬性,否則報錯;
  3. 不能使用 with 語句;
  4. 不能對只讀屬性賦值,否則報錯;
  5. 不能使用字首0表示八進位制數,否則報錯;
  6. 不能刪除不可刪除的屬性,否則報錯;
  7. 不能刪除變數delete prop,會報錯,只能刪除屬性delete global[prop];
  8. eval 不會在它的外層作用域引入變數;
  9. eval 和 arguments 不能被重新賦值;
  10. arguments 不會自動反映函式引數的變化;
  11. 不能使用 arguments.callee;
  12. 不能使用arguments.caller;
  13. 禁止 this 指向全域性物件;
  14. 不能使用 fn.caller 和 fn.arguments 獲取函式呼叫的堆疊;

增加了保留字(比如protected、static和interface)

尤其需要注意this的限制。 ES6 模組之中,頂層的 this 指向 undefined ,即不應該在頂層程式碼使用 this 。

3、export 命令

模組功能主要由兩個命令構成:export和import。 export 命令用於規定模組的對外介面, import 命令用於輸入其他模組提供的功能。

一個模組就是一個獨立的檔案。該檔案內部的所有變數,外部無法獲取。如果你希望外部能夠讀取模組內部的某個變數,就必須使用 export
關鍵字輸出該變數。下面是一個 JS 檔案,裡面使用export命令輸出變數。

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};

export 命令除了輸出變數,還可以輸出函式或類( class )。下面程式碼對外輸出一個函式multiply。

export function multiply(x, y) {
  return x * y;
};

export 輸出的變數就是本來的名字,但是可以使用 as 關鍵字重新命名。

function v1() { ... }
function v2() { ... }
export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};

上面程式碼使用 as 關鍵字,重新命名了函式v1和v2的對外介面。重新命名後,v2可以用不同的名字輸出兩次。需要特別注意的是, export
命令規定的是對外的介面,必須與模組內部的變數建立一一對應關係。

// 寫法一
export var m = 1;
// 寫法二
var m = 1;
export {m};
// 寫法三
var n = 1;
export {n as m};

上面三種寫法都是正確的,規定了對外的介面m。其他指令碼可以通過這個介面,取到值1。它們的實質是,在介面名與模組內部變數之間,建立了一一對應的關係。
function 和 class 的輸出,也必須遵守這樣的寫法。

另外, export 語句輸出的介面,與其對應的值是動態繫結關係,即通過該介面,可以取到模組內部實時的值。

export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);

上面程式碼輸出變數foo,值為bar,500毫秒之後變成baz。 export
命令可以出現在模組的任何位置,只要處於模組頂層就可以。如果處於塊級作用域內,就會報錯。

3、import 命令

使用 export 命令定義了模組的對外介面以後,其他 JS 檔案就可以通過 import 命令載入這個模組。

// main.js
import {firstName, lastName, year} from './profile';
function setName(element) {
	element.textContent = firstName + ’ ’ + lastName;
}

import 命令接受一對大括號,裡面指定要從其他模組匯入的變數名。大括號裡面的變數名,必須與被匯入模組(profile.js)對外介面的名稱相同。

瞭解更多

更多內容參考: https://www.gewuweb.com/sitemap.html