關於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};