hoisting

console.log(a)
var a = 10

會變成類似(會說是類似,因為底層不一定是這樣做)

var a
console.log(a)
a = 10

可以把他

var a = '1'
// A...
var b = 2
// B ...
var c 

想像成這樣

function whatever(a,b,c) {
  // A ...
  // B ...
}('1',1,undefined);

如果有let

var a = '1'
function x() {
  // a ...
  let a = 2
}

先想像成

function whatever(a) {
  function x() {
    // a ...
    let a = 2
    // b ...
  }
}('1')

再想像成let會把前面提到同樣變數砍掉,在let的地方展開成function apply

var a = '1'
function whatever() {
  function x() {
    // a ...
    function whatever2(a) {
      // b ...
    }(2)
  }
}('1')

在Scheme怎麼處理mutual recursion?

據說當初JS有hoisting是為了方便寫mutual recursion。 先不說mutual recursion平常很少用到,先來看看scheme(或ML家族語言)是如何處理mutual recursion

有一個東西叫letrec

(letrec
  [(even? (lambda (x)
            (if (zero? x)
                #t
                (odd? (- x 1)))))
  (odd?   (lambda (x)
            (if (zero? x)
                #f
                (even? (- x 1)))))]
  even?)

在這個範圍都是可以互相參照的,個人比較偏好這種方式啦

例子

(function() {
  var a = b = 5;
})();
 
console.log(b);

b會是global!! 所以印出5

同理

for (var i=0;i<10;i++)
   console.log(i)

console.log(i)

最後會是10

還有function也會hoisting

function test() {
   console.log(a);
   console.log(foo());
    
   var a = 1;
   function foo() {
      return 2;
   }
}
test()

會印 undefined 2

Ref

很詳細的文章

builtin type

  • string 是 Immutable
    • 字面常數是value type
    • new的是reference type
    • 字面常數與new出來的不同
    • 字面常數不能加method上去
var s = 'abc';
var s2 = s.slice(); // 'abc' (a clone)
s == s2 // true

var s3 = new String(s); // object
var s4 = new String(s); // object
s3 == s4 // false

// 用 === 從可怕的隱式轉換拯救自己
  • undefined就是undefined(c的void)

  • null是object

  • falsy value

    • false
    • 0
    • ''
    • null
    • undefined
    • NaN
'' == '0' // false
'' == 0 // true
'0' == 0 // true
' \t\r\n' == 0 // true
false == 'false' // false
false == 0 // true
false == undefined // false
false == null // false
null == undefined // true
NaN == NaN // false

event bubbling

從樹根往下走,走到終點,只有終點的事件,會執行冒泡與捕獲的事件,其他都是看在什麼階段就執行什麼階段的事件。

如果是終點有設定冒泡與捕獲的事件,那事件的執行順序,就看當初加入事件的順序

斬斷鎖鏈

e.stopPropagation (單體攻擊)

// list 的捕獲 
$list.addEventListener('click', (e) => {
  console.log('list capturing');
  e.stopPropagation(); // <--- 這邊這事件就不會繼續下去
}, true)

// list 的捕獲 2
$list.addEventListener('click', (e) => {
  console.log('list capturing2'); // <--- 這邊 會 繼續下去
}, true)

e.stopImmediatePropagation (AOE)

// list 的捕獲
$list.addEventListener('click', (e) => {
  console.log('list capturing');
  e.stopImmediatePropagation(); // <--- 會讓同一層的所有事件停止
}, true)

// list 的捕獲 2
$list.addEventListener('click', (e) => {
  console.log('list capturing2');
}, true)

e.preventDefault (AOE ver.針對browser)

// list_item_link 的冒泡
$list_item_link.addEventListener('click', (e) => {
  e.preventDefault();
}, false)

當點超連結的時候,就不會執行原本預設的行為(新開分頁或是跳轉),而是沒有任何事情發生。

prototype & interface

function newObj(Constructor, arguments) {
  var o = new Object();
  // 讓 o 繼承原型鍊
  o.__proto__ = Constructor.prototype;
  // 執行建構函式
  Constructor.apply(o, arguments);
  // 回傳建立好的物件
  return o;
}

可以想像成Constructor.prototype是class變數與方法的env __proto__就是parent的指標 用apply完成填值的動作

另外,apply與call都是差不多的東西,只是一個是放參數列,一個是給array bind就是會先綁定this成某個Object,只後丟出function