es6的一些小知識點筆記

關於es6的一些筆記:

編程虐我千百遍,我待編程如初戀。
看了不下5遍es6,
馬什麼梅?什麼冬梅?馬冬什麼?奧,馬冬梅啊。
關閉教程之後,馬什麼梅?
馬..馬…馬了個巴子的…又tm忘了。
如果你沒有過目不忘的本領,個人總結的記憶的強弱:
調試bug>實踐>自己寫一遍>看一遍。
下面是我看着阮一峯老師的es6入門叫聲然後自己動手寫的一些筆記,當然也有一部分直接拉取的阮一峯老師的。
如果想看詳細教程:請看es6阮一峯日誌,傳送門:
es6 阮一峯

正文

1.let不存在變量提升。但是var有變量提升。
2.區級作用域{ }類型中如果有let或者const,此區塊不再受到外部影響。

var tmp = 123;
if(ture){
    tmp = 'abc'; //ReferenceError;
    let tmp;
}

3.let不允許重複聲明
4.es5規定,函數只能在頂層作用域和函數作用域之中聲明,不能再塊級作用域聲明,但是瀏覽器沒有遵守這個規定,爲了兼容以前的額舊代碼,還是支持在塊級作用域聲明函數,es6明確允許在塊級作用域之中聲明函數,函數聲明語句類似於let,再塊級作用域之外不可引用。
5.const一旦聲明變量,就必須立即初始化。同時,const也不存在變量提升,必須在聲明後使用,和let一樣,不可重複聲明。
6.for in 循環遍歷對象 簡單示例

例如
var obj ={
    a:'123',
    b:'asdv',
    c:123
}
for(let i in obj){
    //遍歷時候的i是對象名字 也是 a b c
    obj[i]//這取出來的是對象的值
}

Object.keys() 簡單示例

var obj ={
    a:'123',
    b:'asdv',
    c:123
}
Object.keys(obj) //返回一個數組 ['a','b','c']
//然後我們forEach一下
Object.keys(obj).forEach(function(key,i){
    key  //a  b c
    i    //0  1 2
    obj[key] //'123' 'asdv' 123
})

詳細區別傳送門:for in 和 object.keys的詳細區別
for in 會遍歷自定義的枚舉屬性,以及原型鏈上的可枚舉屬性
某些情況下可能按照隨機順序遍歷數組元素。
object.keys 會遍歷自身可枚舉屬性(返回結果爲數組),數組中的屬性名排列順序與使用for in 循環遍歷該對象時返回的順序一致與for in的主要區別在於不能遍歷出原形鏈上的屬性。
7.頂層對象,在瀏覽器環境指的是window對象,在Node指的是global對象。es5之中,頂層對象的屬性與全局變量是等價的。
es6爲了改變這一點,同時又爲了保持兼容性,var命令,function命令聲明的全局變量依舊是頂層對象的屬性,另一方面規定:let,const,class命令聲明的全局變量,不屬於頂層對象的屬性,

var a = 1;
// 如果在 Node 的 REPL 環境,可以寫成 global.a
// 或者採用通用方法,寫成 this.a
window.a // 1

let b = 1;
window.b // undefined

8.解構賦值的例子
es6允許按照一定的模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構。
其實只要按照模板往裏面放入值就行,只要格式一樣就能賦值,非常簡便。
等號右邊的數據結構必須具有Iterator接口
如果賦值不成功,變量的值爲undefined
其中三個點(…)這個代表數組

let [a, b, c] = [1, 2, 3];
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

一些不完全解構的例子:
即使模板不用,也會把相同的部分賦值上去

let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4

解構賦值還可以有他自己的默認值

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

es6內部使用嚴格相等運算符(===)判斷一個位置是否有值,所以只有當一個數組成員嚴格等於undefined時候,默認值纔會生效。

let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null

變量的解構賦值還可以是表達式,但是表達式是惰性求值的,只有在用到的時候纔會求值。
默認值還可以引用解構賦值的其他變量,但該變量必須已經聲明。

let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError: y is not defined

9.對象的解構賦值例子
對象的解構與數組有一個重要的不同。數組的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。

let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined

如果變量名與屬性名不一致,必須寫成下面這樣。

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'

如果要將一個已經聲明的變量用於解構賦值,必須非常小心。

// 錯誤的寫法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

上面代碼的寫法會報錯,因爲 JavaScript 引擎會將{x}理解成一個代碼塊,從而發生語法錯誤。只有不將大括號寫在行首,避免 JavaScript 將其解釋爲代碼塊,才能解決這個問題。

// 正確的寫法
let x;
({x} = {x: 1});

對象的解構賦值,可以很方便地將現有對象的方法,賦值到某個變量。

let { log, sin, cos } = Math;

和數組解構一樣,對象解構賦值也是可以允許有默認值的,匹配的值的時候也是根據(===)來匹配的,如果位置上爲undefined,則判定此位置沒有值,同時也是可以嵌套賦值的,這裏不再過多的贅述。
如果想更多的瞭解點擊傳送門:

對象的解構賦值:詳細


10字符串的解構賦值
字符串也可以解構賦值。這是因爲此時字符串轉換成了一個類似數組的對象

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

類似數組的對象都有一個length屬性,因此還可以對這個屬性解構賦值

let {length : len} = 'hello';
len // 5

11數值和布爾值的賦值解構
解構規則:只要等號右邊的值不是對象或數組,就先將其轉爲對象。由於undefined和null無法轉爲對象,所以對它們進行解構賦值,都會報錯。

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError

數值和布爾值的例子:

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

因爲轉化爲對象後,Object中有toString屬性,所以變量s都能取到值。


12.函數參數的解構賦值
函數的參數也可以使用解構賦值

function() add([x,y]){
    return x+y;
}
add([1,2]);

關於函數的解構賦值,阮一峯老師的教程中還有一個例子,有點看不明白,先記下來。

function move({x = 0, y = 0} = {}) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
function move({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]

這是阮一峯老師對這個代碼的解釋:上面代碼是爲函數move的參數指定默認值,而不是爲變量x和y指定默認值,所以會得到與前一種寫法不同的結果。

除此之外:undefined也會觸發函數參數的默認值;


13.關於圓括號的問題
解構賦值雖然方便了很多,但是對於編譯器來說,一個式子到底是模式,還是表達式,沒辦法重一開始就知道,必須解析到(或者解析不到)等號才能知道
所以建議:只要有可能,就不要再模式中放置圓括號,
ps:個人理解,其實這個模式就是咱們賦值語句的模板,也就是對象中的屬性值。
不能使用圓括號的例子:
(1)變量聲明語句

let [(a)] = [1];

let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};

let { o: ({ p: p }) } = { o: { p: 2 } };

(2)函數參數
函數參數也屬於變量聲明,因此不能帶有圓括號

// 報錯
function f([(z)]) { return z; }
// 報錯
function f([z,(x)]) { return x; }

(3)賦值語句的模式

// 全部報錯
({ p: a }) = { p: 42 };
([a]) = [5];
// 報錯
[({ p: a }), { x: c }] = [{}, {}];

可以使用圓括號的例子只有一種情況:賦值語句的非模式部分,可以使用圓括號。

[(b)] = [3]; // 正確
({ p: (d) } = {}); // 正確
[(parseInt.prop)] = [3]; // 正確

這三個圓括號都是合法的,首先都是賦值語句,而且不是聲明語句,其次它們的圓括號都不屬於模式的一部分,第一個數組的解構賦值,所以不存在對象的屬性值(模式)(其實數組也是有屬性值的,那就是0 1 2 3 這裏就不算了)
第二行語句中,是對象的解構賦值,但是模式是p,而值是d,所以對d用圓括號沒問題,第三個和第一個一樣。


14,關於解構賦值的一些用處。
(1)首先是交換變量的值

//以前最熟悉的寫法
var a = 1;
var b = 2;
var temp;
temp = a;
a = b;
b = temp;
//有了解構賦值以後
var a = 1;
var b = 2;
[a,b] = [b,a]

(2)然後是從函數返回多個值
函數一次只能返回一個值,以前如果要返回多個值的話,就要把數據放到數組中,然後返回這個數組或者一個對象中,然後取出來的時候非常的麻煩,有了解構賦值取出這些數據就變得非常的簡單了。

//數組的例子
function example(){
    return [1,2,3]
}
let [a,b,c] = example();
//對象的例子
function example(){
    return {
        foo:1,
        bar:2
    }
}
let {foo,bar} = example();

(3)函數參數的定義
解構賦值可以方便的將一組參數與變量名對應起來

//如果參數是有次序的值
function([x,y,z]){...}
function([1,2,3]);
//如果參數不是有次序的值,可以利用對象的解構賦值
function({x,y,z}){...}
function({z:3,y:2,x:1});

(4)提取JSON對象中的數據,尤其有用。

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]

(5)函數參數的默認值

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};

字符串

凡事有??的亂碼,均是一個碼點大於0xFFFF的字符。

15.javascript內部,字符以UTF-16的格式存儲,每個字符固定兩個字節,對於那些需要4個字節存儲的字符(unicode碼點大於0xFFFF的字符)javascript會認爲他們是兩個字符。


var s= '?'; //碼點大於0xFFFF 注意不是吉祥的吉
s.length // 2
s.charAt(0) // ''
s.charAt(1) // ''
s.charCodeAt(0) // 55362
s.charCodeAt(1) // 57271

16.字符串的遍歷
es6爲字符串添加了遍歷器接口,使得字符串可以被for of 循環遍歷。

for (let codePoint of 'foo') {
  console.log(codePoint)
}
// "f"
// "o"
// "o"

當然for in 也可以遍歷,只不過要麻煩一些

var str = 'foo';
for (let key in str) {
  console.log(str[key]);
}

但是for of最大的優點就是識別大於0xFFFF的碼點,傳統的for循環無法識別這樣的碼點。

let text = String.fromCodePoint(0x20BB7);
//這個碼點大於0xFFFF所以佔用4個字節。

for (let i = 0; i < text.length; i++) {
  console.log(text[i]);
}
// " "
// " "

for (let i of text) {
  console.log(i);
}
// "?"

17.es5提供charAt()方法,返回字符串給定位置的字符串,但是該方法不能識別大於0xFFFF的字符。

'abc'.charAt(0) // "a"
'?'.charAt(0) // "\uD842"

charAt方法期望返回的是用2個字節表示的字符,但是漢字‘?’佔用了4個字節,charAt(0)表示獲取的4個字節中的前兩個字節,很顯然這是沒法顯示的。
解決的辦法是at()方法。可以識別unicode編號大於0xFFFF的字符,返回正確的字符串

'abc'.at(0) // "a"
'?'.at(0) // "?"

18.一般來說判斷一個字符串是否包含在另一個字符串中,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

19.repeat()
repeat方法返回一個將原字符串重複n次的字符串。

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

規則:
1 參數如果是小數會被取整(個人理解:向上取整)
2 參數如果是負數或者Infinity(無窮),會報錯
3 但是如果參數是0到-1之間的小數,則等同於0,這是因爲會先進行取整運算。0到-1之間的小數,取整以後等於-0,repeat視同爲0
4 參數NaN等同於0
5 如果repeat的參數是字符串,則會先轉化爲數字。

'na'.repeat(2.9);
'na'.repeat(Infinity)
// RangeError
'na'.repeat(-1)
// RangeError
'na'.repeat(-0.9) // ""
'na'.repeat(NaN) // ""
'na'.repeat('na') // ""
'na'.repeat('3') // "nanana"

20 padStart()      padEnd()
這是補全字符串的函數,如果某個字符串不夠制定長度,會在頭部或者尾部補全,padStart()用於頭部補全,padEnd()用於尾部補全。

'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'

'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'

規則:
1 如果原字符串的長度,等於或者大於制定的最小長度,則返回原字符串。
2 如果用來補全的字符串與原字符串,兩者的長度之和,超過了制定的最小長度,則會截去超出位數的額補全字符串。
3 如果省略第二個參數,則會默認使用空格補全長度。

'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
'abc'.padStart(10, '0123456789')
// '0123456abc'
'x'.padStart(4) // '   x'
'x'.padEnd(4) // 'x   '

常見用途
1 爲數值補全指定位數

'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"

2 填充固定格式的字符串

'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"

21模板字符串
以前的javascript語言,輸出模板通常是這樣的:
相當麻煩

$('#result').append(
  'There are <b>' + basket.count + '</b> ' +
  'items in your basket, ' +
  '<em>' + basket.onSale +
  '</em> are on sale!'
);

es6引入了模板字符串來解決這個問題

$('#result').append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

規則:
1 兩端使用反引號來標示,在英文輸入法下按鍵1的左邊的那個按鍵。
2 可以當作普通字符串來使用,也可以定義多行字符串,也可以在字符串中    嵌入變量
3 如果想使用反引號,前面加\轉義
4 使用模板字符串的時候,所有空格和縮進都會被保留在輸出之中。
5 模板字符串之中的嵌入變量,需要將變量名寫在${ }之中。大括號之中可以進行運算,以及對象屬性的引用。還能調用函數。如果大括號之中是字符串,將會原樣輸出。
6 如果大括號之中的值不是字符串,將按照一定的規則轉化爲字符串。比如,大括號中是一個對象,將默認調用對象的toString方法。
7 模板字符串還可以嵌套
如果想看具體實例和更詳細的解說傳送門:阮一峯:模版字符串


22 正則的擴展


23 es6 最好使用0b(0B)或者0o(0O)表示二進制和八進制,在嚴格模式下八進制不再使用以前的0表示了,並且會報錯。
如果要將0b和0o前綴的字符串轉爲十進制,要使用Number方法

Number('0b111')  // 7
Number('0o10')  // 8

24 Number.isFInite()   Number.isNaN()
這兩個方法都是在Number類上添加的方法,所以引用的話,只能Number.xxx();
Number.isFlnite()用來檢查一個數值是否爲有限的,即不是Infinity注意參數類型不是數字,一律返回false;
Number.isNaN()用來檢查一個值是否爲NaN,同樣如果是非數字,則一律返回false;
1 isFinite()
2 isNaN()
3 Number.isFinite();
4 Number.isNaN();
全局函數1 2 和Number類上的函數3 4的區別在於傳統的方法1 2 先調用Number將非數字的值轉化爲數值,在進行判斷,而3 4這兩個新方法只對數值有效,Number.isFinite()對於非數值一律返回false, Number.isNaN()只有對於NaN才返回true,非NaN一律返回false。


25.es6將全局方法parseInt()和parseFloat()移植到Number對象上面,行爲完全保持不變。這樣做的目的是使語言逐步模塊化


26.Number.isInteger()用來判斷一個數值是否爲整數。在javascript中,整數和浮點數採用的是同樣的儲存方法,所以25和25.0被視爲同一個值,如果參數不是數值,Number.isInteger() 返回false

Number.isInteger(25) // true
Number.isInteger(25.1) // false
Number.isInteger(25) // true
Number.isInteger(25.0) // true

javascript採用的是IEEE754標準,數值的儲存爲64位雙精度格式,數值精度最多可以達到53個二進制(1個隱藏位和52個有效位),如果數值的精度超過這個限度,第54位後面的位就會被捨棄,這個時候,Number.isInteger()可能會誤判

Number.isInteger(3.0000000000000002)

上面代碼中,Number.isInteger的參數明明不是整數,但是會返回true。原因就是這個小數的精度達到了小數點後16個十進制位,轉成二進制位超過了53個二進制位,導致最後的那個2被丟棄了。
類似的情況還有,如果一個數值的絕對值小於Number.MIN_VALUE(5E-324),即小於 JavaScript 能夠分辨的最小值,會被自動轉爲 0。這時,Number.isInteger也會誤判。
總之,如果對數據精度的要求較高,不建議使用Number.isInteger()判斷一個數值是否爲整數


27.es6在Math對象上又擴展17個方法。這些方法都是靜態的,只能在Math對象上調用。
ps:es6中加了一個指數運算符(**);
這裏我就不記了,給個阮一峯老師的傳送門:阮一峯:Math對象的擴展


28.函數參數的默認值
es6允許爲函數的參數設置默認值,即直接寫在參數定義的後面。

function log(x,y='world'){
    console.log(x,y='world');
}

好處:1,閱讀代碼的人,可以立即意識到哪些參數是可以省略的,不用查看函數體或者文檔,其次,有利於將來的代碼優化,即使未來的版本在對外接口中,徹底拿掉這個參數,也不會導致以前的代碼無法運行。
參數變量是默認聲明的,所以不能用let或者const再次聲明

function foo(x = 5) {
  let x = 1; // error
  const x = 2; // error
}

使用參數默認值時,參數不能有同名參數。js沒有函數的重載

// 不報錯
function foo(x, x, y) {
  // ...
}

// 報錯
function foo(x, x, y = 1) {
  // ...
}
// SyntaxError: Duplicate parameter name not allowed in this context

函數參數的默認值是惰性求值的。

let x = 99;
function foo(p = x + 1) {
  console.log(p);
}
foo() // 100
x = 100;
foo() // 101

29.參數解構賦值和函數默認值的結合
注意一個例子

function m1({x = 0, y = 0} = {}) {
  return [x, y];
}

// 寫法二
function m2({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}
// 函數沒有參數的情況
m1() // [0, 0]
m2() // [0, 0]

// x 和 y 都有值的情況
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]

// x 有值,y 無值的情況
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]

// x 和 y 都無值的情況
m1({}) // [0, 0];
m2({}) // [undefined, undefined]

m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]

30.參數默認值的位置最好是尾參數。


31.函數的length屬性
指定了默認值之後,函數的length屬性,將返回沒有指定默認值的參數個數。

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2

length的含義是:預期傳入的參數個數,某個參數指定默認值後,預計傳入的參數個數也就不包括這個參數了。

(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1

如果函數的默認值不是尾參數,那麼length將忽略設有默認值參數之後的參數。


32.函數的rest參數
es6引入rest參數用於獲取函數多餘的參數,這樣就不需要arguments對象了,rest是一個真正的數組,所有數組的方法都可以使用,arguments變量是一個類數組,通過Array.prototype.slice.call(arguments)可以將arguments轉化爲數組,注意rest參數必須是最後一個參數,之後不能有其他參數,否則會報錯,函數的length屬性,不包括rest參數。


33.函數的嚴格模式
es5開始,函數內部就可以定義爲嚴格模式,es6做了一點修改,規定:只要函數參數使用了默認值,解構賦值,或者擴展運算符,那麼函數內部就不能顯示的設置爲嚴格模式,否則會報錯。
這是因爲:函數內部的嚴格模式,同樣適用於函數體和函數參數,但是函數執行的時候,先執行函數參數,在執行函數體,這樣就有不合理的地方,只有從函數體之中,才能知道是否以嚴格模式執行,但是參數卻先於函數體執行。
兩種方法可以規避這種限制,第一種是設定全局性的嚴格模式,這是合法的。

'use strict';

function doSomething(a, b = a) {
  // code
}

第二種是把函數包在一個無參數的立即執行函數裏面,然後在外層函數使用嚴格模式。

const doSomething = (function () {
  'use strict';
  return function(value = 42) {
    return value;
  };
}());

34.函數的name屬性
函數的name屬性返回該函數的函數名,這個屬性早就被瀏覽器廣泛支持,但是知道es6才寫入標準。
es6對這個屬性的行爲做了一些修改,如果將一個匿名函數賦值給一個變量,es5的name屬性,會返回空字符串,而es6的name屬性會返回實際的函數名。

var f = function () {};

// ES5
f.name // ""

// ES6
f.name // "f"

如果將一個有函數名字的函數賦值給一個變量,es5和es6都會返回這個具名函數的原名

const bar = function baz() {};

// ES5
bar.name // "baz"

// ES6
bar.name // "baz"

Function構造函數返回的函數實例,name屬性的值爲anonymous。

(new Function).name // "anonymous"

bind返回的函數,name屬性值會加上bound前綴。

function foo() {};
foo.bind({}).name // "bound foo"

(function(){}).bind({}).name // "bound "

35.箭頭函數
es6允許使用箭頭定義函數

var f = v =>v;
//等同於
var f = function(v){
    return v;
}

注意:
1.箭頭函數不需要參數或者有多個參數,使用一個圓括號表示參數部分
2.如果箭頭函數的代碼塊部分多於一條語句,就要使用大括號將他們括起來,並且使用return語句返回。如果你返回的是一個對象,必須在對象外面加上括號,否則會報錯。
3.普通函數中,函數體內的this對象就是使用時所在的對象,但是在箭頭函數中,就是定義時所在的對象這事固定不變的。
4.箭頭函數不可以當構造函數,也就是說不能使用new命令,否則會報錯。
5.不可以使用arguments對象,該對象在函數體內不存在,如果要用,可以用rest參數代替。
6.不可以使用yield命令,因此箭頭函數不能用作Generator函數。

//關於函數體內部this指向的問題。
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
// id: 42

36.雙冒號運算符
箭頭函數可以綁定this對象,大大減少了顯示綁定this對象的寫法(call、apply、bind、)但是箭頭函數並不適合所有場合,所以提出了‘函數綁定’運算符,用來取代call、apply、bind調用。
規則:1.函數綁定運算符(::)雙冒號左邊是對象,右邊是一個函數,該運算符號,會自動將左邊的對象,所有上下文環境(this對象),綁定到右邊的函數上面。
2.如果左邊爲空,右邊是一個對象的方法,則等於將該方法,綁定在該對象上面。
3.如果雙冒號運算符的運算結果還是一個對象,就可以採用鏈式寫法。


37.數組的擴展運算符號
擴展運算符是三個點(…)。它好比是rest參數的逆運算,將一個數組轉爲用逗號分隔的參數序列
數組的擴展運算符可以展開數組,所以不再需要apply方法,將數組轉爲函數的參數了。
擴展運算符的應用:
1.複製數組
2.合併數組
3.與解構賦值的結合
4.與字符串的結合使用
5.實現Iterator接口的對象


38.Array.from()
用於將兩類對象轉爲真正的數組:類似數組的對象和可遍歷的對象
擴展運算符號也可以將某些數據結構轉爲數組,它調用的是遍歷器解構,如果一個對象沒有部署這個接口,就無法轉換,Array.from對任何有length屬性的對象,都能把他轉化爲數組。

let arrayLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
}
Array.from(arrayLike);

39.Array.of返回參數構成的數組,如果沒有參數,就返回一個空數組。


40.copyWithin()
數組實例的copyWithin方法,在當前數組內部,將指定位置的成員複製到其他位置(會覆蓋原有成員),然後返回當前數組。也就是說,使用這個方法,會修改當前數組。


41.find方法,findIndex方法
entries keys values方法
includes 方法
ps:這幾個方法寫了三次了都,都是在草稿箱忘了保存了。
但是有個重點是find和findInex都會發現NaN,彌補了indexOf和lastIndexOf()的不足。


42.數組的空位
forEach(), filter(), reduce(), every() 和some()都會跳過空位。
map()會跳過空位,但會保留這個值
join()和toString()會將空位視爲undefined,而undefined和null會被處理成空字符串。
es6明確指出,數組的空位會轉化爲undefined


43.對象的簡潔表示法
在對象中,es6允許咋變量名和屬性值一樣時,只需寫一個即可

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 ={
    methods:funciton(){
        return 1;   
    }
}
//等同於
const o = {
    methods(){
        return 1;
    }
}

下面是一個混合的例子

let birth = '2000/01/01';

const Person = {

  name: '張三',

  //等同於birth: birth
  birth,

  // 等同於hello: function ()...
  hello() { console.log('我的名字是', this.name); }
};

43.對象的屬性名表達式
使用大括號定義對象es5中定義對象只能

var people = {
    name:'Jhin',
    age:12
}

es6中定義對象的屬性名表達式:

var peopKey = 'foo';
var people = {
    [peopKey]:'thiskey',
    ['a'+'bc']:'thatkey'
}

也可以適用於函數名字

let obj = {
    ['h'+'ello'](){
        return 'hi';
    }
};
obj.hello();//hi

需要注意的是屬性名與簡潔表示法,不能同時使用,會報錯

// 報錯
const foo = 'bar';
const bar = 'abc';
const baz = { [foo] };

// 正確
const foo = 'bar';
const baz = { [foo]: 'abc'};

如果屬性名是個對象,默認情況下會將對象轉化爲字符串,這點要特別小心。


44.Object.is()
es5比較兩個值是否相等,只有兩個運算符,==和===,但是這兩個運算符都有缺點,==號會自動轉化數據類型,後者NaN不等於自身,以及+0等於-0。javascript缺乏一種運算,在所有環境中,只要是兩值是一樣的,他們就應該相等。
Object.is()就此誕生,它用來比較兩個值是否嚴格相等,與嚴格運算符(===)的行爲基本一致。
不同之處也能很簡單:NaN等於NaN,並且
+0不等於-0。;


45.Object.assign()
Object.assign方法用於對象的合併,將源對象(source)的所有可枚舉屬性,複製到目標對象(target)

const target = {a:1};
const source1 = {b:2};
const source2 = {c:3};
Object.assign(target,source1,source2);
target; //{a:1, b:2, c:3}

規則:
1.Object.assign方法的第一個參數是目標對象,其餘的參數都是源對象。
2.如果目標對象和後面的源對象有重複屬性,或者源對象與其他源對象有相同的屬性,那麼後面的會覆蓋前面的屬性。
3.如果只有一個參數,那麼Object.assign會返回這個參數。
4.如果這個參數不是對象,那麼Object.assign會先轉化爲對象然後返回。
5.由於undefined和null無法轉化爲對象,所以當用undefined和null做首參數的時候,就會報錯。
6.如果非對象參數出現在源對象的位置,會首先把非對象參數轉化爲對象,如果不能轉化爲對象,就會跳過,這就意味這,如果undefined和null不在首參數就不會報錯。
7.其他類型的值(數組,字符串,布爾)不在首參數,也不會報錯,單數除了字符串會以數組的形式,拷貝入目標對象,其他值不會殘生任何結果。

const v1 = 'abc';
const v2 = true;
const v3 = 10;

const obj = Object.assign({}, v1, v2, v3);
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

注意點:Object.assign方法實現的是一級屬性深拷貝,二級屬性淺拷貝,也就是說,拷貝得到的二級屬性其實是源對象是屬性的一個引用;更改拷貝後對象的二級屬性,源對象的屬性也會改變。

var  a = {name:'123',age:{detail:10}};
            var  b = Object.assign({},a);

            b.name = '小紅';
            b.age.detail = 12;

            console.log(a.name + ' ' +a.age.detail);//123 12
            console.log(b.name + ' ' +b.age.detail);//小紅 12

目前有四個操作會忽略enumerable爲false屬性。
for—-in循環:只遍歷自身的可枚舉屬性和繼承的可枚舉屬性。
Object.keys():返回對象自身的所有可枚舉屬性。
JSON.stringify():只串行化對象自身的可枚舉屬性。
Object.assign:忽略enumberalbe爲false屬性的,只拷貝對象自身的可枚舉屬性。

注意for—-in會遍歷繼承的屬性,其他三個方法都會忽略繼承的屬性。
儘可能不能for—in 而選擇Object.keys()代替。


46.Object.getOwnPropertyDescriptors();
這個方法會返回投個對象屬性的描述對象。


47.對象的擴展運算符
對象的解構賦值。

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

1.解構賦值要求等號右邊是一個對象,所以如果等號右邊undefined或者null,就會報錯,因爲他們無法轉化爲對象。
2.解構賦值必須是最後一個參數,否則會報錯。

對象的擴展運算符(….)用於取出參數對象的可遍歷屬性,拷貝到當前對象之中。

let z = {a:3,b:4};
let n = {...z};

擴展運算符還可用與合併兩個對象。

let ab = {...a,...b};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章