catch會創建塊作用域
有點驚呆 O_o
聲明提升
函數首先被提升,然後纔是變量。
後面的函數聲明可以覆蓋前面的。
神話般的存在:閉包
閉包是詞法作用域產生的自然結果,這意味着作用域是由聲明的位置決定的。
一個例子觀察閉包
function foo() {
var a = 2;
function bar() {
console.log(a);
}
return bar;
}
var baz = foo();
baz();
foo()
執行完之後,其內部作用域並沒有銷燬,因爲還有baz
指向foo
內部作用域的bar
。
this
this 是在運行時進行綁定的,而不是在編寫時綁定。
有四種綁定場景
(1) 默認綁定
非嚴格模式下綁定到全局對象,嚴格模式下綁定到 undefined
function foo() {
console.log(this.a);
}
var a = 2;
foo(); // 2
'use strict';
function foo() {
console.log(this.a);
}
var a = 2;
foo(); // Uncaught TypeError: Cannot read property 'a' of undefined
(2) 隱式綁定
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo();
(3) 顯式綁定
即 call、apply、bind
(4) new 綁定
this 綁定到新創建的對象
優先級
可以猜到的是
隱式綁定 > 默認綁定
顯式綁定 > 默認綁定
new 綁定 > 默認綁定
隱式綁定和顯示綁定誰的優先級高?
function foo() {
console.log(this.a);
}
var obj1 = {
a: 2,
foo: foo
};
var obj2 = {
a: 3
};
obj1.foo.call(obj2); // 3
顯式綁定 > 隱式綁定
new 綁定和顯式綁定誰的優先級高?
function foo(value) {
this.a = value;
}
var obj = {
a: 2
};
var bar = foo.bind(obj);
var baz = new bar(3);
console.log(baz.a); // 3
new 綁定 > 顯式綁定
所以,new 綁定 > 顯式綁定 > 隱式綁定 > 默認綁定
綁定到null與undefined
如果把 null 或者 undefined 傳入call、apply或者 bind,調用時會被忽略,應用的是默認綁定。
箭頭函數
箭頭函數是根據外層作用域來決定 this
function foo() {
return () => {
console.log(this.a);
}
}
var obj1 = {
a: 2
};
var obj2 = {
a: 3
};
var bar = foo.call(obj1);
bar.call(obj2); // 2
null 和 undefined 沒有對應的包裝對象
只有 number、string、boolean 有包裝對象。
面向對象還是行爲委託?
作者對在 JS 中使用面向對象的行爲狠狠吐槽了一番,包括 class 關鍵字的引入。
這裏不是說面向對象的思想有問題,而是 JS 中”僞面向對象”的寫法好不好。
行爲委託倡導的是直接創建和關聯對象,不把它們抽象成類,而是順着 JS 的 [[Prototype]] 機制寫。
不過,一個不可否認的狀況是:ES6 的 class 讓人更難看清 JS 的真面目了。