es5/es6中新增的方法


ES5中的新增方法

ES5 中給我們新增了一些方法,可以很方便的操作數組或者字符串,這些方法主要包括:

  • 數組方法
  • 字符串方法
  • 對象方法

1.1 數組方法

迭代(遍歷)方法:forEach()、map()、filter()、some()、every();

array.forEach(function(currentValue, index, arr))
    • 讓數組中每個元素都執行一次 fn,相當於 for 循環
    • 不會占用全局變量,結合箭頭函數賊舒服
    • currentValue:當前項的值
    • index:當前項的索引
    • arr:當前數組對象本身
array.map(function(currentValue, index, arr))
    • map() 方法會得到一個新數組, 新數組中包含每次函數調用返回的結果
    • 它返回的是一個新數組
array.filter(function(currentValue, index, arr))
    • filter() 方法創建一個新的數組,新數組中的元素是通過檢查指定數組中符合條件的所有元素,主要用於篩選數組
    • 注意它直接返回一個新數組
    • currentValue: 當前項的值
    • index:當前項的索引
    • arr:當前數組對象本身
array.some(function(currentValue, index, arr))
    • some() 方法用於檢測數組中的元素是否滿足指定條件,即查找數組中是否有滿足條件的元素。
    • 它的返回值是布爾值,如果查找到這個元素,就返回true , 如果查找不到就返回false。
    • 如果找到第一個滿足條件的元素,則終止循環,不再繼續查找。
    • currentValue: 當前項的值
    • index:當前項的索引
    • arr:當前數組對象本身
array.every(function(currentValue, index, arr))
    • every() 方法檢測數組中的所有元素是否滿足指定條件。
    • 所有的元素都返回true,結果才是true

1.2 字符串方法

trim() 方法會從一個字符串的兩端刪除空白字符。

str.trim()
  • trim() 方法並不影響原字符串本身,它返回的是一個新的字符串

1.3 對象方法

  1. Object.keys() 用於獲取對象自身所有的屬性

    Object.keys(obj)
    • 效果類似 for…in

    • 返回一個由屬性名組成的數組

  2. Object.defineProperty() 定義對象中新屬性或修改原有的屬性。

    Object.defineProperty(obj, prop, descriptor)
    • obj:必需。目標對象

    • prop:必需。需定義或修改的屬性的名字

    • descriptor:必需。目標屬性所擁有的特性,以對象形式 { } 書寫

      • value: 設置屬性的值 默認為undefined

      • writable: 值是否可以重寫。true | false 默認為false

      • enumerable: 目標屬性是否可以被枚舉。true | false 默認為 false

      • configurable: 目標屬性是否可以被刪除或是否可以再次修改特性 true | false 默認為false

 

ES6的新增語法

1. let

  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
    // 解析:每次循環都會產生一個塊級作用域,每個塊級作用域中的變量都是不同的,函數執行時輸出的是自己上一級(循環產生的塊級作用域)作用域下的值。

2. const

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.

let、const、var 的區別

  1. 使用 var 聲明的變量,其作用域為該語句所在的函數內,且存在變量提升現象

  2. 使用 let 聲明的變量,其作用域為該語句所在的代碼塊內,不存在變量提升

  3. 使用 const 聲明的是常量,在后面出現的代碼中不能再修改該常量的值

var let const
函數級作用域 塊級作用域 塊級作用域
變量提升 不存在變量提升 不存在變量提升
值可更改 值可更改 值不可更改

3. 解構賦值

ES6中允許從數組中提取值,按照對應位置,對變量賦值。對象也可以實現解構。

按照一定模式,從數組中或對象中提取值,將提取出來的值賦值給另外的變量。

3.1 數組解構

let [a, b, c] = ['pink', 'yellow', 'blue']; //正常解構賦值
console.log(a, b, c);

如果解構不成功,變量的值為undefined。

let [foo] = [];
let [bar, foo] = [1];
let [, c] = ['red', 'yellow'];  //選擇性解構賦值

3.2 對象解構

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'

4. 箭頭函數

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();

注:在對象的方法中也不要用箭頭函數(如果用箭頭函數,就沒法用this),注冊事件的函數也不要用箭頭函數。

  • 面試題解析:
var obj = {
    age: 20,
    say: () => {
        console.log(this.age)
    }
}
obj.say(); // undefined
// 解析:箭頭函數中沒有自己的this,它的this指向箭頭函數定義區域的this。此例中的箭頭函數定義在了obj這個對象中,它是一個對象,不能產生作用域,所以這個箭頭函數被定義在了全局作用域下,所以在調用這個方法的時候this指向window

5. 剩余參數

剩余參數語法允許我們將一個不定數量的參數表示為一個數組。

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']

6. ES6的內置對象擴展

6.1 擴展運算符(展開語法)

  • 擴展運算符可以將數組或者對象轉為用逗號分隔的參數序列。

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];

6.2 構造函數方法:Array.from()

  • 將類數組或可遍歷對象轉換為真正的數組

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)

6.3 實例方法:find()

用於找出第一個符合條件的數組成員,如果沒有找到返回undefined

let ary = [
    { id: 1, name: 'andy' },
    { id: 2, name: 'lily' }
]
let target = ary.find(item => item.id === 2);

6.4 實例方法:findIndex()

用於找出第一個符合條件的數組成員的位置,如果沒有找到返回-1

let ary = [1, 5, 10, 15];
let index = ary.findIndex((value, index) => value > 9); 
console.log(index); // 2

6.5 實例方法:includes()

判斷字符串是否包含另一個字符串,傳統的 js 方法: indexOf 返回值是否等於 -1 ,如果等於 -1說明不包含

es6 中提供了方法 includes() 返回布爾值,表示是否包含給定的值。

[1, 2, 3].includes(2) // true 
1, 2, 3].includes(4) // false
​
let s = 'hello world'
s.includes('hello', 6) // false  第一個參數是需要匹配的數據,第二個參數是從第幾個開始

7. 模板字符串

ES6新增的創建字符串的方式,使用反引號定義 ``。

  • 模板字符串中可以解析變量。

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); // 哈哈哈哈 追不到我吧 我就是這么強大 哈哈哈哈

8. String 的擴展方法

8.1 實例方法:startsWith()和endsWith()

  • startsWith():表示參數字符串是否在原字符串的頭部,返回布爾值
  • endsWith():表示參數字符串是否在原字符串的尾部,返回布爾值
let str = 'Hello world!';
str.startsWith('Hello') // true 
str.endsWith('!')       // true

8.2 實例方法:repeat()

repeat() 方法表示將原字符串重復n次,返回一個新字符串。

'x'.repeat(3)      // "xxx" 
'hello'.repeat(2)  // "hellohello"

9.Set 數據結構

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 數據類型轉換成數組類型,這個時候又可以用到展開符這個好東西了

實例方法

    • add(value):添加某個值,返回 Set 結構本身

    • delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功

    • has(value):返回一個布爾值,表示該值是否為 Set 的成員

    • clear():清除所有成員,沒有返回值

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))

10. Promise

promise 用於更優雅的處理異步請求,其實就是對於回調函數的另一種寫法,可以幫助我們避免回調地獄

回調地獄:比如第二個請求依賴第一個請求的結果進行請求,第三個請求依賴第二個,這樣一層一層嵌套,。。。 為了解決回調順序的不確定性以及地獄,就有了 promise 機制。

1、Promise 一般來講是一個對象, .then方法其實就是 promise 對象的一個方法

2、Promise 構造函數接受一個函數作為參數,在這個函數中,可以進行異步的操作的代碼

3、在這個函數中執行完成異步操作之前,並不是要調用用戶提供的回調函數(不關心回調到底是什么),而是在這個函數中,異步完成之后,只需要去修改當前的promise 的狀態

4、Promise的狀態:

    • pendding :掛起,當前 promise 執行的任務,正在執行中
    • fullfilled: 完成,當前 promise 對象執行的任務,已經完成,並且是成功狀態
    • rejected: 完成,當前 promise 對象執行的任務,已經完成,並且是失敗的狀態

5、Promise 對象的 .then 方法中接收到的成功的回調函數,會在當前的 promise 對象處於成功(fullfilled)狀態的時候自動執行;

      Promise對象的 .then 方法中接收到的失敗的回調函數,會在當前的 promise 對象處於失敗(rejected)狀態的時候自動執行

6、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);
    });
}

7、在 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)
})

8、語法

語法一:

promise.then(
    function() {
        console.log('成功的回調')
    },
    function() {
        console.log('失敗的回調')
    }
)

語法二:

Promise
.then(function() {
    console.log('成功的回調')
})
.catch(function() {
    consloe.log('失敗的回調')
})

語法二和語法一的效果一樣。不過它還有另外一個作用:在執行 resolve 的回調(也就是上面then中的參數)時,如果拋出異常了(代碼出錯了),那么並不會報錯卡死,而是會進到這個catch方法中。

8、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:

    • .then() 得到異步任務的成功信息
    • .catch() 獲取異常信息
    • .finally() 成功與否都會執行(還不是正式標准)
    • Promise.all() 並發處理多個異步任務,所有任務都執行完成才能得到結果
    • 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 的基本用法

    • async 關鍵字用於函數上(async 函數的返回值是 Promise 實例對象)
    • 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);
})

11. 模塊化

模塊化就是把單獨的一個功能封裝到一個模塊(文件)中,模塊之間相互隔離,但是可以通過特定的接口公開內部成員,也可以依賴別的模塊。

模塊化開發的好處:方便代碼的重用,從而提升開發效率,並且方便后期的維護。

ES6默認導出與默認導入

    • 默認到處語法 export default 默認導出的成員
    • 默認導入語法 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,否則會報錯

按需導出與按需導入

    • 默認導出語法 export let s1 = 10
    • 默認導入語法 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'

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM