ES5 中給咱們新增了一些方法,能夠很方便的操做數組或者字符串,這些方法主要包括:html
迭代(遍歷)方法:forEach()、map()、filter()、some()、every();ios
array.forEach(function(currentValue, index, arr))
array.map(function(currentValue, index, arr))
array.filter(function(currentValue, index, arr))
array.some(function(currentValue, index, arr))
array.every(function(currentValue, index, arr))
trim() 方法不影響原字符串自己,它返回的是一個新的字符串es6
str.trim()
Object.keys() 用於獲取對象自身全部的屬性面試
Object.keys(obj)
返回一個由屬性名組成的數組axios
Object.defineProperty() 定義對象中新屬性或修改原有的屬性。數組
Object.defineProperty(obj, prop, descriptor)
descriptor:必需。目標屬性所擁有的特性,以對象形式 { } 書寫promise
configurable: 目標屬性是否能夠被刪除或是否能夠再次修改特性 true | false 默認爲false數據結構
ES6中新增的用於聲明變量的關鍵字。併發
let聲明的變量只在所處於的塊級有效。異步
if (true) { let a = 10; } console.log(a) // a is not defined
注意:使用 var 聲明的變量不具有塊級做用域特性,使用 let 關鍵字聲明的變量具備塊級做用域,能夠防止循環變量變成全局變量。
不存在變量提高
console.log(a); // a is not defined let a = 20;
暫時性死區
var num = 10; if(true) { console.log(num); // num is not defined let num = 20; } // 在if的{}中不會向上一級查找num,由於在這個塊級做用域中用了let關鍵字聲明瞭num,變量num就和{}這個塊級進行了總體綁定,因此在聲明以前使用它會報錯
經典面試題
// 題1 var arr = []; for(var i = 0; i < 2; i++) { arr[i] = function() { console.log(i); } } arr[0](); // 2 arr[1](); // 2 // 解析:變量 i 是全局的,函數執行時輸出的都是全局做用域下的 i 值。 // 題2 let arr = []; for(let i = 0; i < 2; i++) { arr[i] = function() { console.log(i); } } arr[0](); // 0 arr[1](); // 1 // 解析:每次循環都會產生一個塊級做用域,每一個塊級做用域中的變量都是不一樣的,函數執行時輸出的是本身上一級(循環產生的塊級做用域)做用域下的值。
const 用於聲明常量,常量就是值(內存地址)不能變化的量。
具備塊級做用域
if (true) { const a = 10; } console.log(a) // a is not defined
聲明常量時必須賦值
const PI; // Missing initializer in const declaration
常量賦值後,值不能修改。
const PI = 3.14; PI = 100; // Assignment to constant variable.
const ary = [100, 200]; ary[0] = 'a'; ary[1] = 'b'; console.log(ary); // ['a', 'b']; ary = ['a', 'b']; // Assignment to constant variable.
var | let | const |
---|---|---|
函數級做用域 | 塊級做用域 | 塊級做用域 |
變量提高 | 不存在變量提高 | 不存在變量提高 |
值可更改 | 值可更改 | 值不可更改 |
ES6中容許從數組中提取值,按照對應位置,對變量賦值。對象也能夠實現解構。
按照必定模式,從數組中或對象中提取值,將提取出來的值賦值給另外的變量。
若是解構不成功,變量的值爲undefined。
let [a, b, c] = ['pink', 'yellow', 'blue']; //正常解構賦值 console.log(a, b, c);
let [foo] = []; let [bar, foo] = [1]; let [, c] = ['red', 'yellow']; //選擇性解構賦值
使用變量的名字匹配對象的屬性,匹配成功,將對象屬性的值賦值給變量。
let {name, age} = {name: 'andy', age: 18}; // 正常解構賦值 console.log(name, age); // andy 18 let {name: myName, age: myAge} = {name: 'andy', age: 18}; //myName myAge 屬於別名 let {name = 'lily', age } = {name: 'andy', age: 18}; //給name設置了默認值'lily'
ES6中新增的定義函數的方式。
// 語法:() => {} const fn = () => {} fn();
函數體中只有一句代碼,且代碼的執行結果就是返回值,能夠省略大括號
function sum(a, b) { return a + b; } const sum = (a, b) => a + b; sum(10, 20);
若是形參只有一個,能夠省略小括號
function fn (v) { return v; } const fn = v => v;
箭頭函數不綁定 this 關鍵字,它的 this 值是繼承自它的父做用域的,因此箭頭函數不能做爲構造函數。
箭頭函數的 this 值是詞法做用域,也就是說它在定義的時候就被指定了的,並且也不會隨着它調用方法的改變而改變。因此箭頭函數中的this,指向的是函數定義位置的上下文this。
const obj = {name: 'andy'}; function fn() { console.log(this); // obj return () => { console.log(this); // obj } } const resFn = fn.call(obj); resFn();
面試題解析:
var obj = { age: 20, say: () => { console.log(this.age) } } obj.say(); // undefined // 解析:箭頭函數中沒有本身的this,它的this指向箭頭函數定義區域的this。此例中的箭頭函數定義在了obj這個對象中,它是一個對象,不能產生做用域,因此這個箭頭函數被定義在了全局做用域下,因此在調用這個方法的時候this指向window
剩餘參數語法容許咱們將一個不定數量的參數表示爲一個數組。
const sum = (...args) => { let total = 0; args.forEach(item => total += item); return total; } console.log(sum(10, 20)); // 30 console.log(sum(1, 2, 3, 4)); // 10
剩餘參數和解構配合使用
let students = ['andy', 'jack', 'lily']; let [s1, ...s2] = students; console.log(s1, s2); // 'andy', ['jack', 'lily']
擴展運算符能夠將數組或者對象轉爲用逗號分隔的參數序列。
let ary = [1, 2, 3]; ...ary // 1, 2, 3 console.log(...ary); // 1 2 3
擴展運算符能夠應用於合併數組。
// 方法一 let ary1 = [1, 2, 3]; let ary2 = [3, 4, 5]; let ary3 = [...ary1, ...ary2]; // 方法二 ary1.push(...ary2);
將類數組或可遍歷對象轉換爲真正的數組
let oDivs = document.getElementsByTagName('div'); oDivs = [...oDivs];
將類數組或可遍歷對象轉換爲真正的數組
let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
方法還能夠接受第二個參數,做用相似於數組的map方法,用來對每一個元素進行處理,將處理後的值放入返回的數組。
let arrayLike = { "0": 1, "1": 2, "length": 2 } let newAry = Array.from(aryLike, item => item *2)
用於找出第一個符合條件的數組成員,若是沒有找到返回undefined
let ary = [ { id: 1, name: 'andy' }, { id: 2, name: 'lily' } ] let target = ary.find(item => item.id === 2);
用於找出第一個符合條件的數組成員的位置,若是沒有找到返回-1
let ary = [1, 5, 10, 15]; let index = ary.findIndex((value, index) => value > 9); console.log(index); // 2
es6 中提供了方法 includes() 返回布爾值,表示是否包含給定的值。
[1, 2, 3].includes(2) // true 1, 2, 3].includes(4) // false let s = 'hello world' s.includes('hello', 6) // false 第一個參數是須要匹配的數據,第二個參數是從第幾個開始
模板字符串中能夠解析變量。
let name = '張三'; let sayHello = `hello,my name is ${name}`; // hello, my name is zhangsan
模板字符串中能夠保留空格和換行
let result = { name: 'zhangsan', age: 20, sex: '男' } let html = ` <div> <span>${result.name}</span> <span>${result.age}</span> <span>${result.sex}</span> </div> `;
在模板字符串中能夠調用函數。
const sayHello = function () { return '哈哈哈哈 追不到我吧 我就是這麼強大'; }; let greet = `${sayHello()} 哈哈哈哈`; console.log(greet); // 哈哈哈哈 追不到我吧 我就是這麼強大 哈哈哈哈
endsWith():表示參數字符串是否在原字符串的尾部,返回布爾值
let str = 'Hello world!'; str.startsWith('Hello') // true str.endsWith('!') // true
repeat() 方法表示將原字符串重複n次,返回一個新字符串。
'x'.repeat(3) // "xxx" 'hello'.repeat(2) // "hellohello"
ES6 提供了新的數據結構 Set。它相似於數組,可是成員的值都是惟一的,沒有重複的值。
Set自己是一個構造函數,用來生成 Set 數據結構。
const s = new Set();
Set函數能夠接受一個數組做爲參數,用來初始化。
const set = new Set([1, 2, 3, 4, 4]);
例如:利用set去重,獲得一個新數組
let set = new Set([1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]) console.log(set) console.log([...set])
注:set 去重以後獲得的 set 類型的數據,因此還得把這個 set 數據類型轉換成數組類型,這個時候又能夠用到展開符這個好東西了
實例方法
const s = new Set(); s.add(1).add(2).add(3); // 向 set 結構中添加值 s.delete(2) // 刪除 set 結構中的2值 s.has(1) // 表示 set 結構中是否有1這個值 返回布爾值 s.clear() // 清除 set 結構中的全部值
Set 結構的實例與數組同樣,也擁有 forEach 方法,用於對每一個成員執行某種操做,沒有返回值。
s.forEach(value => console.log(value))
promise 用於更優雅的處理異步請求,其實就是對於回調函數的另外一種寫法,能夠幫助咱們避免回調地獄。
回調地獄:好比第二個請求依賴第一個請求的結果進行請求,第三個請求依賴第二個,這樣一層一層嵌套,。。。爲了解決回調順序的不肯定性以及地獄,就有了 promise 機制。
Promise的狀態:
resolve 是一個函數,調用這個函數,就能夠把當前 promise 對象標記成功reject 也是一個函數,調用這個函數,能夠把當前 promise 對象標記失敗
var p = new Promise(function(resolve, reject) { resolve() // 成功時調用 reject() // 失敗時調用 }); p.then(function(res) { // 從resolve獲得正常結果 }, function(res) { // 從reject獲得錯誤信息 })
resolve 和 reject在調用的時候,能夠傳遞數據,這個數據會最終被傳遞到成功或者失敗的回調函數中。
// 封裝一個支持Promise APi的延時函數 function timeOut(time){ return new Promise(function(resolve, reject){ setTimeout(function(){ // 這個回調函數中,不須要涉及任何具體的業務操做 // resolve(123); // 可傳遞數據,這個數據會最終被傳遞到成功回調函數中 reject(); }, time); }); }
在 then 方法中,咱們能夠直接return 數據而不是 Promise 對象,在後面的 then 中就能夠接收到數據了。
then 參數中的函數返回值:
1. 返回 Promise 實例對象:返回的該實例對象會調用下一個 then
2. 返回普通值:返回的普通值會直接傳遞給下一個 then,經過 then 參數中函數的參數接受該值
timeOut(1000) .then(num => { console.log(num + '這是1s後打印的內容') return timeOut(1000) }) .then(num => { console.log(num + '這是2s後打印的內容') return timeOut(1000) }) .then(num => { console.log(num + '這是3s後打印的內容') return timeOut(1000) })
語法一:
promise.then( function() { console.log('成功的回調') }, function() { console.log('失敗的回調') } )
語法二:
Promise .then(function() { console.log('成功的回調') }) .catch(function() { consloe.log('失敗的回調') })
語法二和語法一的效果同樣。不過它還有另一個做用:在執行 resolve 的回調(也就是上面then中的參數)時,若是拋出異常了(代碼出錯了),那麼並不會報錯卡死,而是會進到這個catch方法中。
9. promise 的其餘用法
Promise.all: 只有當傳入的全部 promise 的結果爲 reslove,纔會執行這個 all 的回調函數(即觸發 then 方法執行裏面的代碼),不然只要有一個是 reject,就會執行 catch 方法。
Promise .all([t1, t2, t3, t4, t5]) .then(function(){ console.log("全部異步操做完成了"); } .catch(function() { console.log("嗷嗷~~~有操做出錯了"); }) )
Promise.race:由第一個 promise 返回的狀態決定,若是第一個 promise 返回的結果爲 reslove 就會執行這個race的回調
Promise.race([t1, t2, t3, t4, t5]).then(function(){ console.log("有一個異步率先完成了"); })
經常使用API:
Promise.race() 只要有一個任務完成就能獲得結果
Promise.all([p1, p2, p3]).then(res => { console.log(res); //三個結果的數組 }) Promise.race([p1, p2, p3]).then(res => { console.log(res); })
示例:基於Promise處理Ajax請求:
function queryData(url) { return new Promise(function(resolve, reject){ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if(xhr.readystate !== 4) return; if(xhr.readystate === 4 && xhr.status === 200){ resolve(xhr.responseText); }else{ reject('出錯了'); } } xhr.open('get', url); xhr.send(null); }) } queryData('http://localhost:3000/data') .then(function(res){ console.log(res); }, function(err){ console.log(err) }) //發送屢次請求 queryData('url1') .then(function(data){ return queryData('url2'); }) .then(function(data){ return queryData('url3'); }) .then(function(data){ console.log(data); })
這裏順便叨叨一下 Promise 的語法糖:async/await 的基本用法
await 關鍵字用於 async 函數中(await 能夠獲得異步的結果)
async function queryData(id){ const ret = await axios.get('/data'); return ret; } queryData.then(ret => { console.log(ret); })
使用async後,代碼變得更簡潔,代碼的邏輯和數據流都變得更加清晰。因爲 async 的原理仍是以 Promise 爲基礎,因此部分時候,async 是要和 Promise 配合使用的,它並不能徹底脫離 Promise 獨立運行;await 必須在 async 函數裏使用,不能單獨使用。
多個異步請求的場景
async function queryData(id){ const info = await axios.get('/async1'); const ret = await axios.get(`/async2?info=`+info.data); return ret; } queryData.then(ret => { console.log(ret); })
模塊化就是把單獨的一個功能封裝到一個模塊(文件)中,模塊之間相互隔離,可是能夠經過特定的接口公開內部成員,也能夠依賴別的模塊。
模塊化開發的好處:方便代碼的重用,從而提高開發效率,而且方便後期的維護。
ES6默認導出與默認導入
默認導入語法 import 接收名稱 from ‘模塊標識符’
//當前文件模塊爲 m1.js//定義私有成員a和c let a = 10; let c = 20; let d = 30; function show(){} //將本模塊中的私有成員暴露出去,供其餘模塊使用 export default { a, c, show } //導入模塊成員 import m1 from './m1.js' console.log(m1) //打印輸出的結果爲{a: 10, b: 20, show: [function: show]} //外界訪問不到d,由於它沒有被暴露出去
注意:每一個模塊中,只容許使用惟一的一次 export default,不然會報錯
按需導出與按需導入
默認導入語法import { s1 } from '模塊標識符'
//當前文件模塊爲 m1.js export let s1 = 'aaa' export let s2 = 'bbb' export function say = function(){} //導入模塊成員 import {s1, s2 as ss2, say} from './m1.js' console.log(s1); // aaa console.log(ss2); // bbb console.log(say); // [function: say]
注意:每一個模塊中,可使用屢次按需導出
直接導入並執行模塊代碼
只執行模塊中的代碼,並不須要獲得模塊中向外暴露的成員,此時能夠直接導入並執行模塊代碼。
//當前文件模塊爲 m2.js //在當前模塊中執行一個 for 循環操做 for(let i = 0; i < 3; i++) { console.log(i); } //直接導入並執行模塊代碼 import './m2.js'