ES6的基礎知識(一)

1.ECMAScript 6.0(如下簡稱ES6)。javascript

2.ECMAScript 和 JavaScript 的關係是,前者是後者的規格,後者是前者的其中一種實現。html

3.對ES6支持的瀏覽器:超過 90%的 ES6 語法特性都實現了。java

 

4.Node(nodejs)是 JavaScript 的服務器運行環境(runtime)。node

5.Babel 是一個普遍使用的 ES6 轉碼器,能夠將 ES6 代碼轉爲 ES5 代碼。git

npm install --save-dev @babel/core  //在項目目錄中安裝命令

(1)配置文件.babelrc,存放在項目的根目錄下。用於設置轉碼規則和插件。全部 Babel 工具和模塊的使用,都必須先寫好.babelrces6

//基本格式
{
"presets": [], //設定轉碼規則的:如安裝官方提供的最新規則集:npm install --save-dev @babel/preset-env
"plugins": [] }

將新安裝的規則加入.babelrcgithub

  {
    "presets": [
      "@babel/env"
    ],
    "plugins": []
  }

(2)使用工具@babel/cli進行命令行轉碼ajax

npm install --save-dev @babel/cli  //安裝
#基本用法:

# 轉碼結果輸出到標準輸出 npx babel example.js # 轉碼結果寫入一個文件 #
--out-file 或 -o 參數指定輸出文件 npx babel example.js --out-file compiled.js //單個文件轉碼輸出到compiled.js # 或者 npx babel example.js -o compiled.js # 整個目錄轉碼 # --out-dir 或 -d 參數指定輸出目錄 npx babel src --out-dir lib //整個src目錄轉碼輸出到lib # 或者 npx babel src -d lib # -s 參數生成source map文件 npx babel src -d lib -s

(3)@babel/node模塊,實現ES6的REPL(Read Eval Print Loop:交互式解釋器),能夠直接運行ES6代碼npm

npm install --save-dev @babel/node   //安裝
npx babel-node  //進入REPL環境命令
npx babel-node
> (x => x * 2)(1)  //直接執行表達式代碼
2
# es6.js 的代碼
# console.log((x => x * 2)(1));
npx babel-node es6.js  //直接運行腳本文件
2

(4)使用@babel/register改寫require命令。目的是每當使用require加載.js,.jsx,.es和.es6後綴的文件,會自動先用babel轉碼。它是實時轉碼,因此只適合在開發環境使用。json

npm install --save-dev @babel/register  //安裝

// index.js //在一個名爲index.js的文件引入es6.js
require('@babel/register');  //要首先加載@babel/register
require('./es6.js');  //引入上面的es6.js文件

//使用
node index.js   //直接執行es6.js中的es6代碼,不須要手動對index.js轉碼

(5)babel API:若是代碼須要調用babel API進行轉碼,那麼須要用到@babel/core模塊,參考這裏

(6)使用@babel/polyfill,爲當前環境提供墊片。babel默認只轉換新的javas句法(syntax),不轉換新的API,如Set,Map等全局對象都不會轉碼。

ES6在Array對象新增了Array.from方法。babel就不會進行轉碼,若是想運行這個方法,必須使用babel-polyfill。

http://babeljs.io/docs/usage/options/   //安裝

//在腳本頭部引入
import '@babel/polyfill';
// 或者
require('@babel/polyfill');

(7)使用@babel/standalone模塊,將babel用於瀏覽器環境。

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>  //將代碼插入網頁
<script type="text/babel">
// Your ES6 code
</script>

 

6.let 和 const 命令聲明變量

(1)let

let 相似於var,但聲明的變量只在所在的代碼塊內有效

{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

for循環計數器中就很適合使用let命令

以下例子:

var a = [];
for (var i = 0; i < 10; i++) { //循環變量會泄露爲全局變量
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10
var a = [];
for (let i = 0; i < 10; i++) {  //let 聲明的i每次循環都是一個重新聲明的變量,不過javascript引擎內部會記住上一輪循環的值
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

 

另外:

for (let i = 0; i < 3; i++) { //正確運行是會輸出3次abc,函數內部變量i與循環變量i不在同一個做用域,各自有單獨的做用域
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc

let 不存在變量提高的問題(變量能夠在聲明以前使用)

// var 的狀況
console.log(foo); // 輸出undefined
var foo = 2;

// let 的狀況
console.log(bar); // 報錯ReferenceError
let bar = 2;

let的暫時性死區(TDZ):只要塊級做用域內存在let命令,它所聲明的變量就「綁定」(binding)這個區域,再也不受外部的影響。

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError,
  let tmp; //在塊中暫造成了tmp的封閉做用域tmp,使得tmp不受全局tmp影響,形成了tmp='abc'出現未定義先使用的錯誤
}
if (true) {
  // TDZ開始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ結束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

「暫時性死區」也意味着typeof再也不是一個百分之百安全的操做。

typeof x; // ReferenceError 
let x;

let 不容許在相同的做用域內重複聲明同一變量for(var i =0;i<10;i++){a[i] = function(){console.log(i);}console.log(i);console.log(a[i]);console.log(a[i]())

// 報錯
function func() {
  let a = 10;
  var a = 1;
}

// 報錯
function func() {
  let a = 10;
  let a = 1;
}

let實際爲javascript增長了塊級做用域。有了塊級做用域,使得本來普遍應用的當即執行函數表達式IIFE再也不必要

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

ES6 引入了塊級做用域,明確容許在塊級做用域之中聲明函數。ES6 規定,塊級做用域之中,函數聲明語句的行爲相似於let,在塊級做用域以外不可引用。ES5是不容許的,不過瀏覽器爲了兼容舊代碼,並不會報錯。

考慮到環境致使的行爲差別太大,應該避免在塊級做用域內聲明函數。若是確實須要,也應該寫成函數表達式,而不是函數聲明語句

ES6 的塊級做用域必須有大括號,若是沒有大括號,JavaScript 引擎就認爲不存在塊級做用域。

 

 (2)const

const聲明一個只讀常量,一旦聲明,值不能改變,因此一旦聲明就要當即初始化

const PI = 3.1415;
PI // 3.1415

PI = 3; // TypeError: Assignment to constant variable.

const的做用域與let命令相同,塊級內有效。

const聲明的常量也不提高。

const聲明一樣存在暫時性死區TDZ。

const聲明的常量也是不能重複。

const的本質:並非變量的值不能改動,而是變量指向的那個內存地址所保存的數據不得改動。

對於簡單類型:數值,字符串,布爾值,值就保存再變量指向的那個內存地址,所以等同於常量。

對於複雜類型:對象和數組,變量指向的內存地址,保存的只是一個指向實際數據的指針,保證的是指針不變,而指針指向的實際數據是能夠改變的。

const foo = {};
// 爲 foo 添加一個屬性,能夠成功
foo.prop = 123;  //若是想禁止添加屬性,將對象凍結,可使用const foo = Object.freeze({})
foo.prop // 123  //使用凍結,在嚴格模式時,該語句會報錯。

// 將 foo 指向另外一個對象,就會報錯
foo = {}; // TypeError: "foo" is read-only


//對數組同理
const a = []; a.push('Hello'); // 可執行 a.length = 0;  // 可執行 a = ['Dave'];  // 報錯

除了對象凍結,也應將對象屬性凍結,下面是將對象完全凍結的函數

var constantize = (obj) => {
    Object.freeze(obj);
    Object.keys(obj).forEach((key,i) => {
        if(typeof obj[key] === 'object'){
            constantize(obj[key]);
        }
    });
}

7.變量的解構賦值:從數組和對象中提取值,對變量賦值。

(1)

let a = 1;
let b = 2;
let c = 3;

//以上等價於如下代碼

let [a,b,c] = [1,2,3];
//屬於模式匹配解構賦值
let [foo, [[bar], baz]] = [1, [[2], 3]]; foo // 1 bar // 2 baz // 3 let [ , , third] = ["foo", "bar", "baz"]; third // "baz" let [x, , y] = [1, 2, 3]; x // 1 y // 3 let [head, ...tail] = [1, 2, 3, 4]; head // 1 tail // [2, 3, 4] let [x, y, ...z] = ['a']; // x // "a" y // undefined z // []

//解構不成功的,變量值就是undefined,以下都是:
let [foo] = [];
let [bar,foo] = [1]; //等同於let [bar,foo]=[1,],結果都是foo解構失敗,爲undefine
let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
//以上是不徹底解構

若是右邊不是可遍歷結構,將報錯。

// 報錯
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

只要某種數據結構具備 Iterator 接口,均可以採用數組形式的解構賦值。

(2)

解構默認值

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];  //由於null不嚴格等於undefined
x // null

(3)對象的解構賦值,與數組不同的是,對象的解構賦值依據的屬性同名,而數組依據的位置次序

let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

這實際上說明,對象的解構賦值是下面形式的簡寫:

let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };
let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; //foo是匹配模式,baz纔是變量
baz // "aaa"
foo // error: foo is not defined

對象解構一樣有默認值。

// 錯誤的寫法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

(4)字符串解構

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
let {length : len} = 'hello';
len // 5

還有數值布爾值解構,函數參數解構賦值。

(5)變量解構賦值用途

  • 交換變量的值
let x = 1;
let y = 2;

[x, y] = [y, x];
  • 從函數返回多個值
// 返回一個數組

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一個對象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();
  • 函數參數的定義
// 參數是一組有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

// 參數是一組無次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
  • 提取JSON數據
let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]
  • 函數參數的默認值//避免在函數體內再寫var foo= config.foo ||'default'這樣的語句
jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};
  •  遍歷Map結構
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world
//特別地
// 獲取鍵名
for (let [key] of map) {
  // ...
}

// 獲取鍵值
for (let [,value] of map) {
  // ...
}
  • 輸入模塊的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map")

 

 

https://www.cnblogs.com/libin-1/p/6716470.html

http://caibaojian.com/es6/

https://www.jianshu.com/p/87008f4f8513

https://www.runoob.com/w3cnote/es6-tutorial.html

http://es6.ruanyifeng.com/

相關文章
相關標籤/搜索