1、ES6標準javascript
1.let、var、constjava
①let聲明的變量只在let
命令所在的代碼塊內有效。var聲明的變量在全局都有效,代碼塊內會收到全局其餘地方重複聲明的影響。const將聲明一個沒法重複賦值的變量。編程
②var的變量提高:變量能夠在聲明以前使用,值爲undefined
。let不容許變量提高。數組
③「暫時性死區」(temporal dead zone,簡稱 TDZ):若是區塊中存在let
和const
命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是在聲明以前就使用這些變量,就會報錯。數據結構
④let
不容許在相同做用域內,重複聲明同一個變量。var能夠。app
2.變量的解構賦值編程語言
①基本用法:ide
let [a, b, c] = [1, 2, 3];
②若是解構不成功,變量的值就等於undefined
。函數
③解構賦值容許指定默認值。優化
let [foo = true] = []; foo // true let [x, y = 'b'] = ['a']; // x='a', y='b' let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
④字符串的解構賦值:
const [a, b, c, d, e] = 'hello'; a // "h" b // "e" c // "l" d // "l" e // "o"
相似數組的對象都有一個length
屬性,所以還能夠對這個屬性解構賦值。
let {length : len} = 'hello'; len // 5
⑤使用解構賦值交換變量的值
let x = 1; let y = 2; [x, y] = [y, x];
⑥遍歷遍歷 Map 結構
const map = new Map(); map.set('first', 'hello'); map.set('second', 'world'); for (let [key, value] of map) { console.log(key + " is " + value); }
3.函數的擴展
①利用參數默認值,能夠指定某一個參數不得省略。
function throwIfMissing() { throw new Error('Missing parameter'); } function foo(mustBeProvided = throwIfMissing()) { return mustBeProvided; } foo() // Error: Missing parameter
②ES6 引入 rest 參數(形式爲...變量名
),用於獲取函數的多餘參數。
function add(...values) { let sum = 0; for (var val of values) { sum += val; } return sum; } add(2, 5, 3) // 10
注意,rest 參數以後不能再有其餘參數(即只能是最後一個參數),不然會報錯。
③嚴格模式
'use strict'
④name屬性:調用XXX.name將返回這個XXX函數的函數名。
⑤嵌套的箭頭函數
function insert(value) { return {into: function (array) { return {after: function (afterValue) { array.splice(array.indexOf(afterValue) + 1, 0, value); return array; }}; }}; } insert(2).into([1, 3]).after(1); //[1, 2, 3]
let insert = (value) => ({into: (array) => ({after: (afterValue) => { array.splice(array.indexOf(afterValue) + 1, 0, value); return array; }})}); insert(2).into([1, 3]).after(1); //[1, 2, 3]
可是,一旦不注意,可讀性就會呈幾何級降低。
⑥尾函數優化
函數執行的時候有一個函數棧,在A函數中執行B函數,A函數的執行結果和調用點都會保存在函數棧中,由於B函數調用完會還得返回去執行A函數。當A函數的最後一步操做是執行B函數的時候,顯而易見的,能夠釋放A函數在函數棧上的資源了。
典型應用就是,遞歸函數,只要遞歸函數的最後一步是執行其自己,那麼就會使爆棧的概率大大下降。看一個Fibonacci 數列的例子:
function Fibonacci (n) { if ( n <= 1 ) {return 1}; return Fibonacci(n - 1) + Fibonacci(n - 2); } Fibonacci(10) // 89 Fibonacci(100) // 堆棧溢出 Fibonacci(500) // 堆棧溢出
function Fibonacci2 (n , ac1 = 1 , ac2 = 1) { if( n <= 1 ) {return ac2}; return Fibonacci2 (n - 1, ac2, ac1 + ac2); } Fibonacci2(100) // 573147844013817200000 Fibonacci2(1000) // 7.0330367711422765e+208 Fibonacci2(10000) // Infinity
遺憾的是,是否進行尾函數優化,是由編程語言跟編譯器決定的。ES6支持,可是好比JAVA就不支持這個東西(JAVA不建議使用遞歸)。
4.數組的擴展
①擴展運算符「...」
將一個數組轉爲用逗號分隔的參數序列。
console.log(1, ...[2, 3, 4], 5) // 1 2 3 4 5 // 可與其餘參數一塊兒使用 [...document.querySelectorAll('div')] // [<div>, <div>, <div>] function add(x, y) { return x + y; } const numbers = [4, 38]; add(...numbers) // 42
注意,擴展運算符若是放在括號中,JavaScript 引擎就會認爲這是函數調用。若是這時不是函數調用,就會報錯。
因爲擴展運算符能夠展開數組,因此再也不須要apply
方法,將數組轉爲函數的參數了。
還能夠賦值數組:const a2 = [...a1];
還能夠合併數組:const a4 = [...a1, ...a2];
還能夠將字符串轉爲真正的數組:const a5 = [...'hello'] (任何定義了遍歷器Iterator接口的對象,均可以用擴展運算符轉爲真正的數組。)
Map 和 Set 結構,Generator 函數,均可以使用擴展運算符,好比 Map 結構:
let map = new Map([ [1, 'one'], [2, 'two'], [3, 'three'], ]); let arr = [...map.keys()]; // [1, 2, 3]
5.對象的擴展
①ES6 容許直接寫入變量和函數,做爲對象的屬性和方法(只要你有一個引用,你甚至能夠包括整個宇宙)。
let birth = '2000/01/01'; const Person = { name: '張三', //等同於birth: birth birth, // 等同於hello: function ()... hello() { console.log('個人名字是', this.name); } };
function getPoint() { const x = 1; const y = 10; return {x, y}; } getPoint() // {x:1, y:10}
②屬性遍歷
ES6 一共有 5 種方法能夠遍歷對象的屬性。官方推薦使用Object.keys
返回一個數組,包括對象自身的(不含繼承的)全部可枚舉屬性(不含 Symbol 屬性)的鍵名。
遍歷對象的鍵名,都遵照一樣的屬性遍歷的次序規則。
③Object.assign
方法
Object.assign
方法用於對象的合併,將源對象(source)的全部可枚舉屬性,複製到目標對象(target)。可是,Object.assign
方法實行的是淺拷貝,而不是深拷貝。
const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
一樣的操做也能夠進行對象克隆
function clone(origin) { let originProto = Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto), origin); }
爲對象添加屬性
class Point { constructor(x, y) { Object.assign(this, {x, y}); } }
爲對象添加方法
Object.assign(SomeClass.prototype, { someMethod(arg1, arg2) { ··· }, anotherMethod() { ··· } }); // 等同於下面的寫法 SomeClass.prototype.someMethod = function (arg1, arg2) { ··· }; SomeClass.prototype.anotherMethod = function () { ··· };
6.Symbol變量
①Singleton 模式
// mod.js const FOO_KEY = Symbol.for('foo'); function A() { this.foo = 'hello'; } if (!global[FOO_KEY]) { global[FOO_KEY] = new A(); } module.exports = global[FOO_KEY];
const a = require('./mod.js');
console.log(a.foo);
這同時也是全局變量的設置方案,唔。
7.Set 變量
①成員的值都是惟一的,沒有重複的值。四大方法:add、delete、has、clear。
②Set
函數能夠接受一個數組(或者具備 iterable 接口的其餘數據結構)做爲參數,用來初始化。
// 例一 const set = new Set([1, 2, 3, 4, 4]); [...set] // [1, 2, 3, 4]
③利用Set給數組去重
// 去除數組的重複成員 [...new Set(array)]
給字符串去重
[...new Set('ababbc')].join('') // "abc"
Array.from
方法能夠將 Set 結構轉爲數組。這就提供了去除數組重複成員的另外一種方法。
function dedupe(array) { return Array.from(new Set(array)); } dedupe([1, 1, 2, 3]) // [1, 2, 3]
8.Proxy
Proxy 用於修改某些操做的默認行爲,等同於在語言層面作出修改,因此屬於一種「元編程」(meta programming),即對編程語言進行編程。
其實就是一個攔截器,按照官方的描述,更像是一個C++的運算符重載,跟C#的set構造器有殊途同歸之妙。它幾乎能夠做用於全部對象的行爲,不只僅是傳參。(或許能夠拿來弄一個enum)
一個技巧是將 Proxy 對象,設置到object.proxy
屬性,從而能夠在object
對象上調用。 var object = { proxy: new Proxy(target, handler) };
實現數組讀取負數的索引
function createArray(...elements) { let handler = { get(target, propKey, receiver) { let index = Number(propKey); if (index < 0) { propKey = String(target.length + index); } return Reflect.get(target, propKey, receiver); } }; let target = []; target.push(...elements); return new Proxy(target, handler); } let arr = createArray('a', 'b', 'c'); arr[-1] // c
9.JavaScript Array 對象的方法
經常使用方法:
push() 向數組的末尾添加一個或更多元素,並返回新的長度。
concat() 鏈接兩個或更多的數組,並返回結果(a.concat(b))。
值得注意的是,若a是空的,就不能直接concat。
10.=== 和 ==的區別
===嚴格比較,類型不一樣就是不一樣;==會將兩邊轉換成值再比較,好比string和int,1和‘1’是相等的。