參照阮一峰博客:http://es6.ruanyifeng.com/#README
es6常見題:https://blog.csdn.net/qq_39207948/article/details/80678800
數組用法:https://blog.csdn.net/tang15886395749/article/details/65629898
導航:
1.箭頭函數
2.字符串拓展
3.函數拓展
4.數組拓展
5.對象拓展
一、簡單介紹一下ES6加了些什么?
一、箭頭函數
特點:①.簡化代碼;②改變this的指向,誰創建函數,this就指向誰。
1. 簡單的定義:
胖箭頭函數 Fat arrow functions,又稱箭頭函數,是一個來自ECMAScript 2015(又稱ES6)的全新特性。有傳聞說,箭頭函數的語法=>,是受到了CoffeeScript 的影響,並且它與CoffeeScript中的=>語法一樣,共享this上下文。
箭頭函數的產生,主要由兩個目的:更簡潔的語法和與父作用域共享關鍵字this。接下來,讓我們來看幾個詳細的例子
當需要編寫一個簡單的單一參數函數時,可以采用箭頭函數來書寫,標識名 => 表達式。
這樣就可以省卻 function 和 return 的輸入,還有括號,分號等。箭頭函數是ES6新增加的一個特性。
最直接的感覺就是簡便,當然不可能就是這么一點好處,下面就一起來探討一下。
幾個小細節 :
如果箭頭函數的代碼塊多余一條語句,就必須要使用大括號將其括起來,並且使用return 語句返回。
由於大括號會被解釋位為代碼塊,所以如果箭頭函數直接返回一個對象,必須在外面加上括號。
let
f =
id
=> ({
age:
22,
name:
Alice })
箭頭函數還可以和解構賦值 Destructuring 聯合使用.
const
f = ({
first,
last })
=>
first +
'' +
last;
可以簡化回調函數,大大簡化和縮短代碼行數。
2. 箭頭函數和普通函數的區別(this的指向)
普通函數與箭頭函數有個微小的不同點。 箭頭函數沒有自己的this值 ,其this值是通過繼承其它傳入對象而獲得的,通常來說是上一級外部函數的 this 的指向。
function
f() {
setTimeout(()
=> {
console.
log(
"id:",
this.
id);
},
100);
}
f.
call({
id:
42 });
//id: 42;
這個例子中, setTimeout 的參數是一個箭頭函數, 每隔100毫秒運行一次,如果是普通函
數,執行的 this 應該指向全局對象, 但是箭頭函數會讓 this 總是指向函數所在的對象
箭頭函數里面嵌套箭頭函數會有多少個this呢?
看一個簡單的例子
function
f() {
return ()
=> {
return ()
=> {
return ()
=> {
console.
log(
"id:",
this.
id);
};
};
};
}
f().
call({
id:
42 })()()();
//id: 42
上面的代碼中只有一個 this, 就是函數f的this 。這是因為所有的內層函數都是箭頭函數都沒有自己的this,都是最外層f函數的this。
注意:還有三個變量在箭頭函數中也是不存在的arguments , super, new.target所以順理成章,箭頭函數也就不能再用這些方法call(),apply(),bind(),因為這是一些改變this指向的方法,箭頭函數並沒有this啊。
var
adder = {
base:
1,
add
:
function (
a) {
var
f =
v
=>
v +
this.
base;
return
f(
a);
},
addThruCall
:
function (
a) {
var
f =
v
=>
v +
this.
base;
var
b = {
base:
2 };
return
f.
call(
b,
a);
}
};
console.
log(
adder.
add(
1));
3. 怎么處理好箭頭函數的使用問題呢?
使用非箭頭函數來處理由object.method()語法調用的方法。因為它們會接收到來自調用者的有意義的this值。
在其它場合都使用箭頭函數。
4. 使用箭頭函數的注意點
箭頭函數在參數和箭頭之間不能換行。函數體內的this對象就是定義時所在的對象,而不是使用時所在的對象。
'use strict';
var
obj = {
a:
10 };
Object.
defineProperty(
obj,
"b", {
get
: ()
=> {
console.
log(
this.
a,
typeof
this.
a,
this);
return
this.
a +
10;
// represents global object 'Window', therefore 'this.a' returns 'undefined'
}
});
不可以當作構造函數,簡單說就是不能再使用new命令了,不然會報錯。
var
Foo = ()
=> { };
var
foo =
new
Foo();
// TypeError: Foo is not a constructor
不可以使用arguments 對象,該對象在函數體內不存在,如果實在要用可以用rest代替。
不可以使用yield命令,箭頭函數不可用作Generator函數。
值得注意的一點就是this對象的指向是可變的,但在箭頭函數內是固定的。
5. 總結
箭頭函數是我最喜歡的ES6特性之一。使用=>來代替function是非常便捷的。但我也曾見過只使用
=>來聲明函數的代碼,我並不認為這是好的做法,因為=>也提供了它區別於傳統function,其所
獨有的特性。我個人推薦,僅在你需要使用它提供的新特性時,才使用它。
當只有一條聲明語句(statement)時, 隱式 return。
需要使用到父作用域中的this。
二、字符串的一些新特性
1.字符的 Unicode 表示法
2.codePointAt()
3.String.fromCodePoint()
ES5 提供String.fromCharCode方法,用於從碼點返回對應字符,但是這個方法不能識別 32 位的 UTF-16 字符(Unicode 編號大於0xFFFF)。
String.
fromCharCode(
0x20BB7)
// "ஷ"
上面代碼中,String.fromCharCode不能識別大於0xFFFF的碼點,所以0x20BB7就發生了溢出,最高位2被舍棄了,最后返回碼點U+0BB7對應的字符,而不是碼點U+20BB7對應的字符。
ES6 提供了String.fromCodePoint方法,可以識別大於0xFFFF的字符,彌補了String.fromCharCode方法的不足。在作用上,正好與codePointAt方法相反。
String.
fromCodePoint(
0x20BB7)
// "𠮷"
String.
fromCodePoint(
0x78,
0x1f680,
0x79) ===
'x
\u
D83D
\u
DE80y'
// true
上面代碼中,如果String.fromCodePoint方法有多個參數,則它們會被合並成一個字符串返回。
注意,fromCodePoint方法定義在String對象上,而codePointAt方法定義在字符串的實例對象上。
4.字符串的遍歷器接口
5.normalize()
6.includes(), startsWith(), endsWith()
傳統上,JavaScript 只有indexOf方法,可以用來確定一個字符串是否包含在另一個字符串中。ES6 又提供了三種新方法。
1.includes():返回布爾值,表示是否找到了參數字符串。
2.startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。
3.endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。
let
s =
'Hello world!';
s.
startsWith(
'Hello')
// true
s.
endsWith(
'!')
// true
s.
includes(
'o')
// true
這三個方法都支持第二個參數,表示開始搜索的位置。
let
s =
'Hello world!';
s.
startsWith(
'world',
6)
// true
s.
endsWith(
'Hello',
5)
// true
s.
includes(
'Hello',
6)
// false
上面代碼表示,使用第二個參數n時,
endsWith的行為與其他兩個方法有所不同。它針對前n個字符,而其他兩個方法針對從第n個位置直到字符串結束。
7.repeat():repeat方法返回一個新字符串,表示將原字符串重復n次。
'x'.
repeat(
3)
// "xxx"
'hello'.
repeat(
2)
// "hellohello"
'na'.
repeat(
0)
// ""
參數如果是小數,會被取整。
'na'.
repeat(
2.9)
// "nana"
如果repeat的參數是負數或者Infinity,會報錯。
'na'.
repeat(
Infinity)
// RangeError
'na'.
repeat(-
1)
// RangeError
但是,如果參數是 0 到-1 之間的小數,則等同於 0,這是因為會先進行取整運算。0 到-1 之間的小數,取整以后等於-0,repeat視同為 0。
'na'.
repeat(-
0.9)
// ""
參數NaN等同於 0。
'na'.
repeat(
NaN)
// ""
如果repeat的參數是字符串,則會先轉換成數字。
'na'.
repeat(
'na')
// ""
'na'.
repeat(
'3')
// "nanana"
8.padStart(),padEnd()
ES2017 引入了字符串補全長度的功能。如果某個字符串不夠指定長度,會在頭部或尾部補全。padStart()用於頭部補全,padEnd()用於尾部補全。
'x'.
padStart(
5,
'ab')
// 'ababx'
'x'.
padStart(
4,
'ab')
// 'abax'
'x'.
padEnd(
5,
'ab')
// 'xabab'
'x'.
padEnd(
4,
'ab')
// 'xaba'
上面代碼中,padStart和padEnd一共接受兩個參數,第一個參數用來指定字符串的最小長度,第二個參數是用來補全的字符串。
如果原字符串的長度,等於或大於指定的最小長度,則返回原字符串。
'xxx'.
padStart(
2,
'ab')
// 'xxx'
'xxx'.
padEnd(
2,
'ab')
// 'xxx'
如果用來補全的字符串與原字符串,兩者的長度之和超過了指定的最小長度,則會截去超出位數的補全字符串。
'abc'.
padStart(
10,
'0123456789')
// '0123456abc'
如果省略第二個參數,默認使用空格補全長度。
'x'.
padStart(
4)
// ' x'
'x'.
padEnd(
4)
// 'x '
padStart的常見用途是為數值補全指定位數。下面代碼生成 10 位的數值字符串。
'1'.
padStart(
10,
'0')
// "0000000001"
'12'.
padStart(
10,
'0')
// "0000000012"
'123456'.
padStart(
10,
'0')
// "0000123456"
另一個用途是提示字符串格式。
'12'.
padStart(
10,
'YYYY-MM-DD')
// "YYYY-MM-12"
'09-12'.
padStart(
10,
'YYYY-MM-DD')
// "YYYY-09-12"
9.matchAll()
matchAll方法返回一個正則表達式在當前字符串的所有匹配
10.模板字符串
11.實例:模板編譯
12.標簽模板
13.String.raw()
14.模板字符串的限制
三、函數的一些新屬性
1.函數參數的默認值
基本用法:
ES6 之前,不能直接為函數的參數指定默認值,只能采用變通的方法。
function
log(
x,
y) {
y =
y ||
'World';
console.
log(
x,
y);
}
log(
'Hello')
// Hello World
log(
'Hello',
'China')
// Hello China
log(
'Hello',
'')
// Hello World
上
面代碼檢查函數log的參數y有沒有賦值,如果沒有,則指定默認值為World。這種寫法的缺點在於,如果參數y賦值了,但是對應的布爾值為false,則該賦值不起作用。就像上面代碼的最后一行,參數y等於空字符,結果被改為默認值。
為了避免這個問題,通常需要先判斷一下參數y是否被賦值,如果沒有,再等於默認值。
if (
typeof
y ===
'undefined') {
y =
'World';
}
ES6 允許為函數的參數設置默認值,即直接寫在參數定義的后面。
function
log(
x,
y =
'World') {
console.
log(
x,
y);
}
log(
'Hello')
// Hello World
log(
'Hello',
'China')
// Hello China
log(
'Hello',
'')
// Hello
可以看到,ES6 的寫法比 ES5 簡潔許多,而且非常自然。下面是另一個例子。
function
Point(
x =
0,
y =
0) {
this.
x =
x;
this.
y =
y;
}
const
p =
new
Point();
p
// { x: 0, y: 0 }
除了簡潔,ES6 的寫法還有兩個好處:首先,閱讀代碼的人,可以立刻意識到哪些參數是可以省略的,不用查看函數體或文檔;其次,有利於將來的代碼優化,即使未來的版本在對外接口中,徹底拿掉這個參數,也不會導致以前的代碼無法運行。
參數變量是默認聲明的,所以不能用let或const再次聲明。
function
foo(
x =
5) {
let
x =
1;
// error
const
x =
2;
// error
}
上面代碼中,參數變量x是默認聲明的,在函數體中,不能用let或const再次聲明,否則會報錯。
...
2.rest 參數
ES6 引入 rest 參數(形式為...變量名),用於獲取函數的多余參數,這樣就不需要使用arguments對象了。rest 參數搭配的變量是一個數組,該變量將多余的參數放入數組中。
function
add(...
values) {
let
sum =
0;
for (
var
val
of
values) {
sum +=
val;
}
return
sum;
}
add(
2,
5,
3)
// 10
上面代碼的add函數是一個求和函數,利用 rest 參數,可以向該函數傳入任意數目的參數。
下面是一個 rest 參數代替arguments變量的例子。
// arguments變量的寫法
function
sortNumbers() {
return
Array.
prototype.
slice.
call(
arguments).
sort();
}
// rest參數的寫法
const
sortNumbers = (...
numbers)
=>
numbers.
sort();
上面代碼的兩種寫法,比較后可以發現,rest 參數的寫法更自然也更簡潔。
arguments對象不是數組,而是一個類似數組的對象。所以為了使用數組的方法,必須使用Array.prototype.slice.call先將其轉為數組。rest 參數就不存在這個問題,它就是一個真正的數組,數組特有的方法都可以使用。下面是一個利用 rest 參數改寫數組push方法的例子。
function
push(
array, ...
items) {
items.
forEach(
function (
item) {
array.
push(
item);
console.
log(
item);
});
}
var
a = [];
push(
a,
1,
2,
3)
注意,rest 參數之后不能再有其他參數(即只能是最后一個參數),否則會報錯。
// 報錯
function
f(
a, ...
b,
c) {
// ...
}
函數的length屬性,不包括 rest 參數。
(
function (
a) { }).
length
// 1
(
function (...
a) { }).
length
// 0
(
function (
a, ...
b) { }).
length
// 1
3.嚴格模式
從 ES5 開始,函數內部可以設定為嚴格模式。
function
doSomething(
a,
b) {
'use strict';
// code
}
ES2016 做了一點修改,規定只要函數參數使用了默認值、解構賦值、或者擴展運算符,那么函數內部就不能顯式設定為嚴格模式,否則會報錯。
pasting
// 報錯
function
doSomething(
a,
b =
a) {
'use strict';
// code
}
// 報錯
const
doSomething =
function ({
a,
b }) {
'use strict';
// code
};
// 報錯
const
doSomething = (...
a)
=> {
'use strict';
// code
};
const
obj = {
// 報錯
doSomething({
a,
b }) {
'use strict';
// code
}
};
這樣規定的原因是,函數內部的嚴格模式,同時適用於函數體和函數參數。但是,函數執行的時候,先執行函數參數,然后再執行函數體。這樣就有一個不合理的地方,只有從函數體之中,才能知道參數是否應該以嚴格模式執行,但是參數卻應該先於函數體執行。
// 報錯
function
doSomething(
value =
070) {
'use strict';
return
value;
}
上面代碼中,參數value的默認值是八進制數070,但是嚴格模式下不能用前綴0表示八進制,所以應該報錯。但是實際上,JavaScript 引擎會先成功執行value = 070,然后進入函數體內部,發現需要用嚴格模式執行,這時才會報錯。
雖然可以先解析函數體代碼,再執行參數代碼,但是這樣無疑就增加了復雜性。因此,標准索性禁止了這種用法,只要參數使用了默認值、解構賦值、或者擴展運算符,就不能顯式指定嚴格模式。
兩種方法可以規避這種限制。第一種是設定全局性的嚴格模式,這是合法的。
'use strict';
function
doSomething(
a,
b =
a) {
// code
}
第二種是把函數包在一個無參數的立即執行函數里面。
const
doSomething = (
function () {
'use strict';
return
function (
value =
42) {
return
value;
};
}());
4.name 屬性
函數的name屬性,返回該函數的函數名。
function
foo() { }
foo.
name
// "foo"
這個屬性早就被瀏覽器廣泛支持,但是直到 ES6,才將其寫入了標准。
需要注意的是,ES6 對這個屬性的行為做出了一些修改。如果將一個匿名函數賦值給一個變量,ES5 的name屬性,會返回空字符串,而 ES6 的name屬性會返回實際的函數名。
var
f =
function () { };
// ES5
f.
name
// ""
// ES6
f.
name
// "f"
5.箭頭函數
6.雙冒號運算符
箭頭函數可以綁定this對象,大大減少了顯式綁定this對象的寫法(call、apply、bind)。但是,箭頭函數並不適用於所有場合,所以現在有一個提案,提出了“函數綁定”(function bind)運算符,用來取代call、apply、bind調用。
函數綁定運算符是並排的兩個冒號(::),雙冒號左邊是一個對象,右邊是一個函數。該運算符會自動將左邊的對象,作為上下文環境(即this對象),綁定到右邊的函數上面。
foo::
bar;
// 等同於
bar.
bind(
foo);
foo::
bar(...
arguments);
// 等同於
bar.
apply(
foo,
arguments);
const
hasOwnProperty =
Object.
prototype.
hasOwnProperty;
function
hasOwn(
obj,
key) {
return obj::
hasOwnProperty(
key);
}
如果雙冒號左邊為空,右邊是一個對象的方法,則等於將該方法綁定在該對象上面。
var
method =
obj::
obj.
foo;
// 等同於
var
method = ::
obj.
foo;
let
log = ::
console.
log;
// 等同於
var
log =
console.
log.
bind(
console);
如果雙冒號運算符的運算結果,還是一個對象,就可以采用鏈式寫法。
import {
map,
takeWhile,
forEach }
from
"iterlib";
getPlayers()::
map(
x
=>
x.
character())::
takeWhile(
x
=>
x.
strength >
100)::
forEach(
x
=>
console.
log(
x));
7.尾調用優化
尾調用(Tail Call)是函數式編程的一個重要概念,本身非常簡單,一句話就能說清楚,就是指某個函數的最后一步是調用另一個函數。
四、數組的一些新特性
https://blog.csdn.net/wbiokr/article/details/65939582
1.擴展運算符
2.Array.from()
3.Array.of()
4.數組實例的 copyWithin()
5.數組實例的 find() 和 findIndex()
6.數組實例的 fill()
7.數組實例的 entries(),keys() 和 values()
8.數組實例的 includes()
9.數組實例的 flat(),flatMap()
10.數組的空位
四、對象的一些新特性
1.對象寫法:允許直接寫入變量和函數,作為對象的屬性和方法。這樣的書寫更加簡潔。
變量
const
foo =
'bar';
const
baz = {
foo };
baz
// {foo: "bar"}
// 等同於
const
baz = {
foo:
foo };
屬性
function
f(
x,
y) {
return {
x,
y };
}
// 等同於
function
f(
x,
y) {
return {
x:
x,
y:
y };
}
f(
1,
2)
// Object {x: 1, y: 2}
方法
const
o = {
method() {
return
"Hello!";
}
};
// 等同於
const
o = {
method
:
function () {
return
"Hello!";
}
};
屬性的遍歷
ES6 一共有 5 種方法可以遍歷對象的屬性。
(1)for...in
for...in循環遍歷對象自身的和繼承的可枚舉屬性(不含 Symbol 屬性)。
(2)Object.keys(obj)
Object.keys返回一個數組,包括對象自身的(不含繼承的)所有可枚舉屬性(不含 Symbol 屬性)的鍵名。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一個數組,包含對象自身的所有屬性(不含 Symbol 屬性,但是包括不可枚舉屬性)的鍵名。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一個數組,包含對象自身的所有 Symbol 屬性的鍵名。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys返回一個數組,包含對象自身的所有鍵名,不管鍵名是 Symbol 或字符串,也不管是否可枚舉。
以上的 5 種方法遍歷對象的鍵名,都遵守同樣的屬性遍歷的次序規則。
首先遍歷所有數值鍵,按照數值升序排列。
其次遍歷所有字符串鍵,按照加入時間升序排列。
最后遍歷所有 Symbol 鍵,按照加入時間升序排列。
https://www.cnblogs.com/liutie1030/p/5997446.html