1. 程式人生 > >談談程式碼中的this

談談程式碼中的this

  js中我們常常會遇到this,this的具體指向問題對於很多同學來說是很懵懂的;就想lz剛開始接觸時候就是一臉的懵逼,經常被一些題目轉的眼花繚亂。那麼今天lz就跟大家一起交流一下這個this的指向問題!

  背景:不久前有個同事給我們發了一道有關this的題目,於是便有了今天的故事。如下題:

class D0XX {
  constructor () {
    this.attr = {};
  }
  init (config) {
    this.assign(config)
    return this;
  }
  assign (config) {
    
this.attr.afterClose = config.afterClose; } close(){ if(typeof this.attr.afterClose === 'function'){ this.attr.afterClose(); } } } class T0XX{ init(){ this.openPop() } openPop(){ new D0XX().init({ afterClose(){ console.log(
this) } }).close() } } new T0XX().init(); //請問打印出結果是什麼?

  一、且擱下此題目,我們先談談this的指向的以下幾個情況;

  1.1.指向全域性物件上;

    我們在一般的函式呼叫中的this是直接指向我們的全域性物件的,比如:

function globalThis(){
    console.log(this.name);//今天天氣真冷哇
} 
var name = '今天天氣真冷哇'
globalThis();

setTimeout(function
(){ console.log(this.name2); },1000); var name2 = '過了一秒鐘,我就更冷了'

    這裡的setTimeout裡面的this是指向window物件的!

  1.2.指向上文物件

    通俗點就是,哪個物件看上了我,我就跟誰,比如:

function foo() {
    console.log(this.a);
}
var obj = {
    a: '李四',
    foo: foo
}
var a = '張三';
obj.foo(); //李四  看前面是哪個物件(obj),於是this跟obj一見鍾情就好上了
var bar = obj.foo;
bar();//張三 你以為的以為。。 前面說過看物件,沒物件,那就只能全域性物件上茫茫人海只為尋她

  1.3.指向那個‘類’

    我們一般用建構函式進行呼叫時,會產生一個this始終是指向這個‘類’,我們複習下new 一個物件發生了什麼: 

     1.建立一個全新的物件。

     2.這個物件會被執行[[Prototype]]連線。

     3.這個新物件會繫結到函式呼叫的this

     4.執行這個函式裡的程式碼。

     5.如果函式沒有返回其他物件,則自動返回這個新物件。

function fun() {
  this.a = 1;
  this.b = 2;
}
var instance = new fun();
console.log(instance.a);//1

  1.4.箭頭函式this指向當前作用域

    箭頭函式this指向取決於外層的函式作用域或全域性作用域,而且箭頭函式的繫結無法修改,即使是new繫結也不可以。

document.onclick = ()=>{
    console.log(this) //window
}
document.onclick=function(){
    console.log(this) //document
}

  二、如何改變this的繫結關係

    2.1.顯式繫結

    在此之前,相信你已經用過很多次applycall、bind函數了,使用這三個函式可以直接為你要執行的函式指定this,所以這種方式稱為顯式繫結。

function foo () {
  console.log(this.a)
}
var obj = {
  a: 2
}
foo.call(obj) // 2

function foo (something) {
  console.log(this.a, something)
  return this.a + something
}
var obj = {
  a: 2
}
var bar = foo.bind(obj); // bind返回一個繫結到obj上的新函式
var b = bar(3)
console.log(b)
var a = "window's a"
foo('!')

  如上就可以通過這種顯式的方法進行改變繫結關係了;

  三、迴歸到之前同事的題目上

  通過以上的分析,我們就能夠很清楚的分析出以上的答案是指向this.attr這個物件的,別看題目裡又有new字元又有return this;這些東西,很容易讓人迷糊;但是如果我們能掌握住this的這幾種指向情況,相信會易容反掌的多;

  四、如果改動以上的題目你還知道麼?

class D0XX {
  constructor () {
    this.attr = {}
  }
  init (config) {
    this.assign(config)
    return this
  }
  assign (config) {
    this.afterClose = config.afterClose
  }
  close(){
      if(typeof this.afterClose === 'function'){
          this.afterClose()
      }
  }
}
class T0XX{
    init(){
        this.openPop()
    }
    openPop(){
        new D0XX().init({
            afterClose(){
                console.log(this)
            }
        }).close()
    }
}
new T0XX().init()
//請問打印出結果是什麼?

  最後,小Tip~就是之所以demo中可以使用鏈式呼叫是因為init方法中return出了this;這就跟jQuery中的鏈式呼叫有了異曲同工之妙;

  如有不妥,歡迎指教!