Stan Blog

學習過程中的一些記錄

[JaveScript] this 的細節

一般函式的 this

console.log(this);

global
  browser: window


function a(){
  console.log(this);
}

a();  // 結果 window

四種情況

  1. 直接執行 -> global (window)
  2. 作為物件的成員函式執行 -> 該物件
  3. 作為 DOM 的事件偵聽函式 -> 該 DOM
  4. 作為建構函式 -> 建構出來的實例
const obj = {
  name: 'object',
  a(){
  console.log(this);
  },
};

obj.a();
// 結果是 物件本身

const b = obj.a;

b();
// 結果是 window
<button id="btn">btn</button>

function a(){
  console.log(this);
};

btn.addEventListener('click', a);
// 結果是 DOM 本身
function A(){
  console.log(this);
};
const x = new A();
// 結果是 new 出來的物件

題目:

function a(){
  console.log(this); // 結果是 obj
};
const obj = {};
obj.a = a;

obj.a();


const obj = {
  a(){
    console.log(this); // 結果是 obj
    function b(){
      console.log(this); // 結果是 window, 因為是直接執行
    }
    b();
  }
}
obj.a();
function a(){
  console.log(this); // 結果是 btn
}
const obj = {a};
btn.addEventListener('click', obj.a());
function a(){
  console.log(this); // 結果是 window
}
const obj = {
  b(){
    return function (){
      console.log(this); // 結果是 btn, obj.b()(函式) 執行以後, 裡面的 this 就是 btn
      a();
    }
  }
};
btn.addEventListener('click', obj.b());
function a(){
  console.log(this); // 結果是 btn
}
const obj = {
  a(){
    return a;
  }
}
btn.addEventListener('click', obj.a());
function MyClass(){

}
const x = new MyClass;
x.addEventListener('loaded', function()
  console.log(this); // 如果 x 不為 DOM, 結果不一定, 要看 class 怎麼寫的
})

箭頭函式的 this 永遠等於他外面的 this

const a = () => {
  console.log(this); // 結果是 window
}
const obj = {
  a: ()=>{
    console.log(this); // 結果是 window
  }
}
btn.addEventListener('click', a);
obj.a();


function a(){
  // console.log(this);
  const b = ()=>{
    console.log(this); // 結果是 btn
  }
  b();
}
btn.addEventListener('click', a);

vue 組件的 this 使用箭頭函式要先確定裡面沒有使用到 this, 否則結果可能不如預期

<div id="app">
  <button
    @click="test"
  >
    btn
  </button>
</div>

const vm = new Vue({
  el: '#app',
  computed:{
    value(){
      console.log(this); // 結果是 vm 這個實例(組件)
    }
  }
  methods:{
    test(){
      console.log(this); // 結果是 vm 這個實例(組件)
    },
  },
  watch:{
    value(){
        console.log(this); // 結果是 vm 這個實例(組件)
    }
  }
});

bind/apply/call 的 this

一般函式 bind: 把函式的 this 綁定到物件上,產生新的函式

<button id="btn">btn</button>

function a(){
  console.log(this);
}

const obj = {};
const b = a.bind(obj);
btn.addEventListener('click', b); // 結果是 {}

apply:
<button id="btn">btn</button>

function add(){
  console.log(this);
  console.log(x + y);
}

add(3,5); // 結果 window 與 8

add.apply(0, [3, 5]); // 結果 numbwe{0} 與 8
add.apply(btn, [3, 5]); // 結果 btn 與 8
/*
  apply(context, [array]);
  context 要綁定的東西, 同 bind()。傳入的是什麼 this 就會變成傳入的那個
*/

call: 與 apply 很像,差別在後面的參數 不限數量 (不是陣列)

<button id="btn">btn</button>

function add(){
  console.log(this);
  console.log(x + y);
}

add(3,5); // 結果 window 與 8

add.call(0, 3, 5); // 結果 numbwe{0} 與 8
add.call(btn, 3, 5); // 結果 btn 與 8

箭頭函式

  const add = (x, y) => {
    console.log(this);
    console.log(x + y);
  }

  const b = add.bind(btn); // 結果 window 與 8
  b(3, 5);

  add.apply(btn, [3, 5]); // 結果 window 與 8
  add.call(btn, 3, 5); // 結果 window 與 8

  /*
    bind、apply、call 對箭頭函式是無效的
  */

Q&A

1.
  Vue
    new Vue( {
      el:"#app",
      methods: {
        test: () => this // 是 window
      },
    } )
    // 小括號是函式,大括號是物件

  Jquery + Vue
    function init() {
      new Vue({
        el:"#app",
        methods: {
          test: () => this // 是 window
        },
      })
    }

    document.addEventListener("ready", init); // 結果是 document

    $(document).ready(init); // 不一定,要看他函式怎麼寫
    Mylib.ready(init); // 不一定,要看他函式怎麼寫
2.
// 取得被點擊 menu 的 id,顯示被點擊的 context
  <span data-id='1' class="menu">A</span>
  <span data-id='2' class="menu">B</span>
  <span data-id='3' class="menu">C</span>
  <br>
  <span data-id='3' class="context">AA</span>
  <span data-id='3' class="context">BB</span>
  <span data-id='3' class="context">CC</span>

  $('.menu').click(function(){
   const id = $(this).data('id');
   console.log(id);

   $('.context').hide();
   $('.context[data-id="${id}"]').show();
  })
3.
  Vue 處理 SEO
    1. pre-render -- 適用於動態內容不多
    2. Server side rendering (SSR) -- 適用於動態內容多

ps: 箭頭函式不能作為建構式


Ref:

Comments

comments powered by Disqus