This in JavaScript

這篇文章咱們來理解下js中的this關鍵字es6

在開始以前,咱們先定義幾個規則面試

  1. 函數做爲方法調用, 也就是用.的方式
  2. new的方式
  3. applycallbind的方式
  4. 函數做爲自由函數調用

第一種規則,函數做爲方法調用

this指向的就是調用方法的對象瀏覽器

let obj = {
    name: 'len',
    sayName: function() {
        console.log(this)
    }
}

obj.sayName() // { name: 'len', sayName: [Function: sayName] }
複製代碼

第二種規則

this 指向的就是新建立的對象,咱們都知道,使用new關鍵字的時候,會建立一個新的對象bash

let obj = {
    name: 'len',
    sayName: function() {
        console.log(this)
    }
}

new obj.sayName() // sayName {}
複製代碼

第三種規則

這時候,this指向的就是調用bind,apply,call方法的第一個參數(下面例子中的obj)babel

function fn() {
    console.log(this)
}

let obj = {
    value: 5
}

let boundFn = fn.bind(obj)

boundFn() // { value: 5 }
fn.call(obj) // { value: 5 }
fn.apply(obj) // { value: 5 }
複製代碼

第四種規則

在瀏覽器中, 這時候this指向的就是就是window對象閉包

function foo() {
    console.log(this)
}

foo() // Window{}
複製代碼

規則中的組合狀況

const obj = {
    value: 'hi',
    printThis: function() {
        console.log(this)
    }
}
const print = obj.printThis

// 規則1,this指向的就是obj
obj.printThis()  // {value: 'hi', printThis: f} 
// 規則4,this指向的就是Window
print() // Window {}
複製代碼
const obj1 = {
    value: 'hi',
    printThis: function() {
        console.log(this)
    }
}

const obj2 = {value: 17}

// 規則1和3的組合, 規則3的優先級大於規則1
obj1.print.call(obj2) // {value: 17}

// 規則1和規則2的組合,規則2的優先級大於規則1
new obj1.print() // {}
複製代碼

閉包中的this

var name = 'window'
let object = {
    name: 'len',
    sayName: function() {
        return function() {
            return this.name
        }
    }
}

console.log(object.sayName()()) // window
複製代碼

上面爲何打印window呢?咱們拆開來看app

let firsr = object.sayName()
first() // 這是做爲單獨函數調用的,也是就是上面的'規則4',因此this天然就指向window了
複製代碼

es6箭頭函數的this

箭頭函數沒有本身的this,請看:函數

// es6
function foo() {
    setTimeout(() => {
        console.log(this)
    })
}

// es5
function foo() {
    var _this = this
    setTimeout(function() {
        console.log(_this)
    }, 1000)
}

foo() // Window{}
new foo() // foo{}
這樣就又回到了上面的規則了。
複製代碼

上面es5代碼是我用在線babel編譯es6代碼獲得的。從上面咱們能夠看出,箭頭函數是沒有本身的this的,它其實是保存了父級做用域的this,而後在箭頭函數裏面調用的都是父級做用域的this。也正是由於箭頭函數沒有this,因此天然而然咱們就不能使用call,apply,bind來改變this的指向了。學習

最後,來個面試題

class Animal() {
    constructor(type) {
        this.type = type
    }
    
    say(val) {
        setTimeout(() => {
          console.log(this);
          console.log(this.type + " says " + val);
        }, 1000)
    }
}

// es6的class裏面的方法都是定義在prototype上的
console.log(Animal.prototype) // 在瀏覽器中 {constructor: f, say: f}

const animal = new Animal('animal')
animal.say('hi') // 1s later console log "Animal{type: 'animal'}" and "animal says hi"
複製代碼

咱們將上面的改動一下ui

class Animal() {
    constructor(type) {
        this.type = type
    }
    
    say(val) {
        // 這裏沒有使用箭頭函數,這裏的setTimeout造成了一個閉包,this指向的是window
        setTimeout(function() {
          console.log(this);
          console.log(this.type + " says " + val);
        }, 1000)
    }
}

const animal = new Animal('animal')
animal.say('hi') // Window {} / undefined says hi
複製代碼

總結: js中的this仍是挺好理解。只要本身用心去理解,相信你能夠作到的。好了,就到這了,若是以爲文章有什麼問題,能夠在下面留言探討下。畢竟都是在學習,沒有不出錯的。謝謝理解!

相關文章
相關標籤/搜索