一、對象的擴展 1.1對象屬性名錶達式 ES6可以在JSON中使用[]包裹一個key的名字。此時這個key將用表達式作為屬性名(被當做變數求值),這個key值必須是字元串。 1.2 Object.assign()方法 該方法用於對象的合併,將源對象的所有可枚舉的屬性,複製到目標對象。 Object. ...
一、對象的擴展
1.1對象屬性名錶達式
ES6可以在JSON中使用[]包裹一個key的名字。此時這個key將用表達式作為屬性名(被當做變數求值),這個key值必須是字元串。
var a = 'name' var obj = { [a] : "小明", age:12, sex:"男" } console.log(obj.name)
1.2 Object.assign()方法
該方法用於對象的合併,將源對象的所有可枚舉的屬性,複製到目標對象。
Object.assign()方法的第一個參數是目標對象,後面的參數都是源對象。
let obj1 = {a:1}; let obj2 = {a:2, b:3}; let obj3 = {b:4, c:5}; Object.assign(obj1,obj2,obj3) console.log(obj1) console.log(obj2) console.log(obj3)
註意:
l 它沒有返回值,會直接改變Object.assign()中的第一個參數對象
l 後面可以羅列無限個對象,如果目標對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆蓋前面的屬性
如果該參數不是對象,則會先轉成對象,然後返回。
typeof Object.assign(2) // "object"
由於undefined和null無法轉成對象,所以如果它們作為參數,就會報錯。
Object.assign(undefined) // 報錯 Object.assign(null) // 報錯
1.3 Object.keys()方法
它可以將一個對象所有的鍵名(key)轉為一個數組對象,並返回:
let o = {a: 1, b: 2, c: 3}; console.log(Object.keys(o)); //[ 'a', 'b', 'c' ]
1.4 Object.values()方法
它可以將一個對象所有的鍵值(value)轉為一個數組對象,並返回:
let o = {a: 10, b: 20, c: 33}; console.log(Object.values(o)); //[ 10, 20, 33 ]
1.5 Object.entries()方法
它可以將一個對象所有的鍵名(key)和鍵值(value)轉為一個數組對象,並返回:
let o = {a: 10, b: 20, c: 33};
console.log(Object.entries(o));
1.6 Object.is()
ES5 比較兩個值是否相等,只有兩個運算符:相等運算符(==)和嚴格相等運算符(===)。它們都有缺點,前者會自動轉換數據類型,後者的NaN不等於自身,以及+0等於-0。JavaScript 缺乏一種運算,在所有環境中,只要兩個值是一樣的,它們就應該相等。
ES6 提出“Same-value equality”(同值相等)演算法,用來解決這個問題。Object.is就是部署這個演算法的新方法。它用來比較兩個值是否嚴格相等,與嚴格比較運算符(===)的行為基本一致。
console.log(Object.is('a','a')); //true console.log(Object.is({}, {})); //false console.log(Object.is([], [])); //false 不同之處只有兩個:一是:+0不等於-0,二是NaN等於自身。 console.log(+0 === -0); //true console.log(NaN === NaN); //false console.log(Object.is(+0, -0)); //false console.log(Object.is(NaN, NaN)); //true
二、字元串的擴展
2.1定義字元串``反引號
之前定義字元串,必須使用以下定界符
""或''
它們的缺點是在做連字元串的時候,不方便:
var name = "小明"; var age = 12; var str = "你好,我是" + name + "我今年" + age + "歲"; console.log(str)
ES6中用``來做定界符:
var str = `你好`; console.log(str) console.log`str` console.log(typeof str)
var name = "小明"; var age = 12; var str = `你好,我是${name}我今年${age}歲`; console.log(str)
註意:只有``中能夠用${}嵌套變數
動態求值:
var str = `今年是${2016 + 2}`; console.log(str); //2018
能寫簡單運算、函數調用、變數、Math函數、數組表達式方法(map、reduce、filter、join)、三元運算符
function sum(a,b){ return a + b; } var str1 = `哈${Math.random()}哈`; var str2 = `哈${sum(3,4)}哈`; var str3 = `哈${5 > 10 ? true : false}哈`; console.log(str1) console.log(str2) console.log(str3)
2.2字元串方法
以前JavaScript只有indexOf方法,可以用來確定一個字元串是否包含在另一個字元串中。
ES6又提供了三種新方法:
includes() 返回Boolean值,檢查字元串或數組中是否存在某項
startsWith() 返回Boolean值,檢查參數字元串是否在原字元串的開頭
endsWith() 返回Boolean值,檢查參數字元串是否在原字元串的結尾
var url = "http://www.aiqianduan.com/"; console.log(url.includes("www")); //true console.log(url.startsWith("http")); //true console.log(url.endsWith("com/")); //true
這三個方法都支持第二個參數,表示開始搜索的位置:
let s = 'Hello world!'; console.log(s.includes('Hello', 6)) //false console.log(s.startsWith('world', 6)) //true console.log(s.endsWith('Hello', 5)) //true
上面代碼表示,使用第二個參數n時,endsWith的行為與其他兩個方法有所不同。它針對前n個字元,而其他兩個方法針對從第n個位置直到字元串結束。
repeat()返回一個新的字元串能夠將原字元串重覆n次
console.log('★'.repeat(10))
三、數組的擴展
3.1 find和findIndex方法
數組實例的find方法,用於找出第一個符合條件的數組成員,它不會遍歷完整的數組。它的參數是一個回調函數,所有數組成員依次執行該回調函數,直到找出第一個返回值為true的成員,然後返回該成員,就結束。如果沒有符合條件的成員,則返回undefined。
let arr = [2,3,4,5,6,7,8,9,10,11,12]; let item = arr.find(function(item){ return item > 7; }) console.log(item)
數組的findIndex()方法的用法和find一樣,返回第一個符合條件的數組成員的下標位置,如果所有的成員都不符合,則返回-1。
let arr = [2,3,4,5,6,7,8,9,10,11,12]; let index = arr.findIndex(function(item){ return item > 7; }) console.log(index); //6
3.2 Array.from()方法
使用“...”可以類數組對象變為真正的數組。
什麼是類數組對象?就是對象的鍵名都是0、1、2、3、4...,並且有length屬性,可以被枚舉。
var obj = { 0 : 100, 1 : 200, 2 : 300, length:3 } var arr= Array.from(obj); console.log(obj) console.log(arr)
最常見的類數組對象是arguments:
function fun(){ console.log([...arguments]); } fun(1,2,3,4)
3.3 Array.of()方法
它可以將零散的值變為數組
let arr = Array.of(3,4,5,6,7,8);
console.log(arr)
3.4 includes()方法
驗證數組中是否存在某一項:
let arr = [3,4,5,88,100]; console.log(arr.includes(88)); //true console.log(arr.includes(888)); //false
該方法的第二個參數表示搜索的起始位置,預設為0。如果第二個參數為負數,則表示倒數的位置,如果這時它大於數組長度
(比如第二個參數為-4,但數組長度為3),則會重置為從0開始。
[1, 2, 3].includes(3, 3); // false [1, 2, 3].includes(3, -1); // true
沒有該方法之前,我們通常使用數組的indexOf方法,檢查是否包含某個值。
indexOf方法有兩個缺點,一是不夠語義化,它的含義是找到參數值的第一個出現位置,所以要去比較是否不等於-1,表達起來不夠直觀。二是,它內部使用嚴格相等運算符(===)進行判斷,這會導致對NaN的誤判。
[NaN].indexOf(NaN) // -1
includes使用的是不一樣的判斷演算法,就沒有這個問題。
[NaN].includes(NaN) // true
3.5 fill()數組填充
var arr = new Array(10).fill("★"); console.log(arr)
3.6 for of遍歷
增加了一種數組的遍歷方法,叫for of遍歷,通常配合arr.entries()
var arr = ['白板','么雞','二條','三餅','四筒']; for(var v of arr){ console.log(v) }
var arr = ['白板','么雞','二條','三餅','四筒']; for(var [k,v] of arr.entries()){ console.log(k,v) }
四、ES6中函數的新特性
4.1箭頭函數(重點)
ES6 允許使用“箭頭”(=>)定義函數:
註意:
l => 是一個完整的運算符,不能拆開 = >
l 箭頭函數一定是匿名函數,要使用“=”賦值接收某一個匿名的箭頭函數,來給這個匿名的箭頭函數命名。
函數的擴展:http://es6.ruanyifeng.com/#docs/function
l 【function的基本簡化】
const sum = function(a, b){ return a + b; }
等價於,現在用箭頭函數的定義:
const sum = (a, b)=>{ return a + b; }
【return和{}、()都可以簡化】
const sum = (a,b)=> a + b;
console.log(sum(4,5))
如果箭頭函數中,只有一條return語句時,可以簡化“{}”和return
言外之意:如果語句不止一條,必須加“{}”和return語句
如果箭頭函數形參變數中,只有一個參數,可以不寫形參變數的“()”圓括弧
const mianji = r => 3.14 * r * r
console.log(mianji(10))
如果箭頭函數不需要參數,就使用一個圓括弧代表參數部分。
const f = ()=> 5 // 等價於 const f = function(){ return 5; }
由於“{}”被解析為函數體,所以如果箭頭函數直接返回一個對象,必須在對象外加上圓括弧,否則報錯。
// const fun = (id,name)=> {"id": id, "name": name} //報錯 const fun = (id,name)=> ({"id": id, "name": name}) console.log(fun(10001,"小明"))
可以連續寫箭頭函數,表示函數的嵌套,外層的函數返回了一個函數。
const fun = a=> b=> a + b;
console.log(fun(10)(5))
等價於下麵兩種寫法:
const fun = (a)=>{ return (b)=>{ return a + b; } }
function fun(a){ return function(b){ return a + b; } }
註意:箭頭函數有幾個使用註意點。
(1)函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
(2)不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。
(3)不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用 rest 參數代替。
(4)不可以使用yield命令,因此箭頭函數不能用作 Generator 函數。
上面四點中,第一點尤其值得註意。this對象的指向是可變的,但是在箭頭函數中,它是固定的。
4.2函數的剩餘參數
ES6 引入 rest 參數(形式為...變數名),用於獲取函數的多餘參數,這樣就不需要使用arguments對象了。rest 參數搭配的變數是一個數組,該變數將多餘的參數放入數組中。
箭頭函數和普通函數一樣,也可以使用ES6的預設參數和剩餘參數:
const fun = (a,...b)=>{
console.log(a)
console.log(b)
}
fun(1,2,3,4,5,6);
4.3函數的預設參數
ES6允許為函數的參數設置預設值,即直接寫在參數定義的後面:
const sum = (a, b=10)=>{ return a + b; } console.log(sum(3,4)); //7 console.log(sum(3)); //13
在函數的形參中賦值了預設值10,表示如果調用的時候沒有傳入b的值,預設值才會生效。
4.4箭頭函數的上下文
以前說的判斷上下文
規則1:直接圓括弧調用fn(),此時this是window 規則2:對象打點調用obj.fn(),此時this是obj 規則3:數組中枚舉函數調用arr[3](),此時this是arr 規則4:定時器調用函數setInterval(fn , 10),此時this是window 規則5:按鈕的事件監聽oBtn.onclick = fn,此時this是oBtn 規則6:call和allpay可以指定,fn.call(obj),此時this是obj 規則7:用new調用函數,new fn(),此時this是秘密新創建的空白對象。 上面的規則,不適用於箭頭函數!
箭頭函數的上下文是什麼規則呢?
箭頭函數的上下文,是這個函數定義時所處的上下文,而不是看如何調用的。
箭頭函數定義時所在的函數內的this是誰,這個箭頭函數的this終身是誰,不能被改變。
l 題目1:應用場景,之前定時器經常要進行備份,現在有箭頭函數就不需要備份了:
var obj = { a : 10, fn: function(){ setInterval(()=>{ console.log(this.a) },1000) } } obj.fn()
紅色這個函數的上下文是obj,此時箭頭函數的上下文就繼承自obj對象,而不是window。
l 題目2:fun函數裡面有一個箭頭函數,並且箭頭函數執行了
function fun(){ const fn = ()=>{ console.log(this.a) } fn(); } var laowang = { a : 666, fun : fun } laowang.fun();
因為fun函數是laowang打點調用的,所以fun函數的上下文是laowang,此時箭頭函數的上下文就是laowang
因為箭頭函數的上下文,是箭頭函數定義時,所在函數的上下文。
l 相等於在外部備份了一次this:
function fun(){ var self = this; const fn = function(){ console.log(self.a) } fn(); } var laowang = { a : 666, fun : fun } laowang.fun();
l 題目3:
var obj = { say : function(){ var f1 = ()=>{ console.log(this); //obj setTimeout(()=>{ console.log(this); //obj }) } f1(); } } obj.say();
因為f1定義是所處的函數中的this指向obj,setTimeout的箭頭函數this繼承自f1,所以不管有多少層嵌套都是obj。
題目3的延伸:
var obj = { say : function(){ var f1 = function(){ console.log(this); //window setTimeout(()=>{ console.log(this); //window }) } f1(); } } obj.say();
結果:window,因為箭頭函數在定義的時候它所處的環境相當於window,所以在箭頭函數內部的this就是window(node環境沒有window,可以在瀏覽器執行)
也就是說,箭頭函數的上下文取決於如何被定義,而不是如何被調用,正好和之前普通function相反。
進一步說,箭頭函數上下文不能被改變。
題目4:
function fun(){ const fn = ()=>{ console.log(this.a) } const xiaohua = { a : 9999999 } fn.call(xiaohua); //call和apply都不能改變箭頭函數的上下文 } var laowang = { a : 666, fun : fun } laowang.fun();
輸出還是laowang的a,就是666,箭頭函數上下文終身不能改。
箭頭函數不能被call、apply
function還沒有下崗
如果需要一個可變的上下文函數,用function
如果需要一個自動備份外部上下文的函數,用箭頭函數
4.5 bind()綁定上下文
只有function能被bind(),箭頭函數不能被bind()
一個函數如果被bind()指向了某個對象,此時這個函數上下文將終身綁定到這個對象,永不改變,call、apply都沒有改變。
註意:bind()只綁定上下文,但不會執行函數,和call、apply不太一樣
function fun(){ console.log(this.a); } var laowang = { a : 666 } var xiaozhang = { a : 8888 } fun = fun.bind(laowang); //fun函數的上下文終身在是laowang fun(); //即使圓括弧調用fun函數,也是laowang fun.call(xiaozhang); //call和apply也不能改變,還是laowang fun.apply(xiaozhang); fun = fun.bind(xiaozhang); //再次bind也無效,還是laowang setInterval(fun,1000); //定時器也不能改變它
只要寫一遍bind(),沒有任何方法可以改變函數的this指向。
4.6雙冒號運算符
箭頭函數可以綁定this對象,大大減少了顯式綁定this對象的寫法(call、apply、bind)。但是,箭頭函數並不適用於所有場合,所以現在有一個提案,提出了“函數綁定”(function bind)運算符,用來取代call、apply、bind調用。
函數綁定運算符是併排的兩個冒號(::),雙冒號左邊是一個對象,右邊是一個函數。該運算符會自動將左邊的對象,作為上下文環境(即this對象),綁定到右邊的函數上面。
foo::bar; // 等同於 bar.bind(foo); foo::bar(...arguments); // 等同於 bar.apply(foo, arguments);
4.7對象中函數的簡化
var result = Object.keys(obj).map(item=>({ "label": item, "children" : obj[zimu].map(pinpai=>({ "label" : pinpai.brand , "children": pinpai.series.map(chexi=>({ "label" : chexi })) })) }));
var obj = { a : 100, fun : function(){ console.log(this.a); } }
等價於:
var obj = { a : 100, fun(){ console.log(this.a); } } obj.fun();
不等於:
var obj = { a : 100, fun:()=>{ console.log(this.a); } } obj.fun();
4.8 babel翻譯它們
翻譯前 |
翻譯後 |
|
|
箭頭函數就是自動備份了this。
練習:下麵有一個對象,不改變原來的對象,創建新的obj2對象,將id為2那個車主的地區變為“中國”。
var obj1 = { "nowshow": 8, "nowType":"All", "dataArr":[ { "id":1, "brand":"賓士", "price":50, "saler":{ "name":"王尼瑪", "provice":"德國" } }, { "id":2, "brand":"寶馬", "price":20, "saler":{ "name":"李全蛋", "provice":"南韓" } } ] };練習
var obj2 = { ...obj1, "dataArr":obj1.dataArr.map((item)=>{ if(item.id == 2){ return { ...item, saler:{ ...item.saler, provice:"中國" } } } return item; }) } console.log(JSON.stringify(obj2))答案
五、類(構造函數)
5.1 ES6類的新寫法
原來定義一個類,是用構造函數,用new調用。