深入淺出:了解JavaScript的ES6、ES7新特性


參照阮一峰博客: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新增加的一個特性。
     let f = v => v;
最直接的感覺就是簡便,當然不可能就是這么一點好處,下面就一起來探討一下。
幾個小細節 :
如果箭頭函數的代碼塊多余一條語句,就必須要使用大括號將其括起來,並且使用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)是函數式編程的一個重要概念,本身非常簡單,一句話就能說清楚,就是指某個函數的最后一步是調用另一個函數。

8.函數參數的尾逗號

四、數組的一些新特性

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

 


免責聲明!

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



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