this的五種不一樣情形

this的五種不一樣情形

默認狀況

在默認的,純粹的函數調用時,視做全局性調用,此時的this指向全局對象Global,在瀏覽器環境下,也即window對象。json

window.x = 'Jackie'

function func() {
  console.log(this.x)
}

func() // Jackie

在嚴格模式("use strict")下,會禁止this指向全局對象,此時的this會是undefined數組

做爲對象的方法調用

此時this指向調用這個方法的對象。瀏覽器

var x = 'Property of Window'

var obj = {}
obj.x = 'Property of obj'
obj.f = function () {
    console.log(this.x)
}

obj.f() // Property of obj

// 值得注意的狀況
var f = obj.f
f() // Property of Window

callapplybind 的顯式綁定

callapplybind均可以改變一個函數的this指向。app

callapply

callapply會將它們的調用對象的this指向它們的第一個參數。函數

function f () {
  console.log(this.x)
}

var x = 'Property of Window'

var obj = {
  x: "Property of obj"
}

f.apply(obj)     // "Property of obj"

當傳入的第一個參數爲undefined,或者不傳入參數時,在非嚴格模式下,自動會將this指向全局對象Global,在瀏覽器裏是window對象,嚴格模式下則會是undefinedthis

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

f.apply()             // window
f.apply(undefined)     // window

function ff () {
  'use strict'
  console.log(this)
}
ff.apply()             // undefined
ff.apply(undefined) // undefined

callapply沒有本質區別。惟一的區別在於:prototype

call()方法接受的是若干個參數的列表,而apply()方法接受的是一個包含多個參數的數組指針

bind

bind和前面二者也並未有什麼本質的區別,只不過bind將第一個參數綁定當調用函數的this上,並將這個函數返回(不執行)。code

function f () {
  console.log(this.x)
}

var x = 'Property of Window'

var obj = {
  x: "Property of obj"
}

var ff = f.bind(obj)
ff() // "Property of obj"

構造函數

當一個函數被當作構造函數,用new關鍵字新建一個對象的時候,這個函數內部的this以及原型鏈上的this都會指向這個新建的對象。對象

function Jackie(para) {
  this.para = para
  console.log(this)
}
Jackie.prototype.log = function(){
  console.log(this)
}

Jackie('hehe')                 // Window
var p = new Jackie('haha')     // Jackie {para: "haha"}
p.log()                     // Jackie {para: "haha"}

其餘值得注意的綁定

放在超時代碼裏

JavaScript中超時調用的代碼都是在全局做用域中執行的,所以函數中this的值會指向window對象,在嚴格模式下也同樣。由於超時調用的代碼都會有一個隱式綁定:setTimeout(f, time) == setTimeout(f.bind(window), time)

"use stric"
var x = 'Property of Window'

var obj = {}
obj.x = 'Property of obj'
obj.ff = function () {
    setTimeout(
        function () {
            console.log(this.x)
        }, 100)
}

obj.ff()     // Property of Window

// 能夠這麼解決問題
obj.fff = function () {
    var that = this
    setTimeout(
        function () {
            console.log(that.x)
        }, 100)
}
obj.fff()     // Property of obj

事件監聽函數中的this

事件監聽函數中的this指向監聽對象。

var one = document.getElementById('one')
one.onclick = function () {
  console.log(this)
};

one.click() // <div id="one"></div>

箭頭函數

箭頭函數中this的指向,在函數定義時即綁定完畢,且後續沒法更改。

var obj = {
  x: 1
}

var f1 = () => {
  console.log(this)
}
f1.apply(obj) // Window

var f2 = function () {
  var f3 = () => {
    console.log(this)
  }
  return f3
}

var f4 = f2.apply(obj)
f4() // Object {x: 1}

一個更神奇的例子,超時調用的代碼在定義時,綁定了this的指向。

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 }); // id: 42

綁定的優先級

var obj = {x: 0, name: 'obj'}
var robj = {x: -1, name: 'robj'}
var factory = function (x) {
  this.x = x
  console.log(this)
}

var factoryBind = factory.bind(obj)
robj.factory = factoryBind
robj.factory(2) // Object {x: 2, name: "obj"},做爲方法的綁定的優先級低於bind的顯式綁定

factoryBind.call(robj, 3) // Object {x: 3, name: "obj"},call的優先級低於bind
console.log(robj) // Object {x: -1, name: "robj", factory: function},未對robj進行修改
console.log(obj) // Object {x: 3, name: "obj"},修改的是obj,由於this指針指向未變化

var p = new factoryBind(4) // factory {x: 4}
console.log(p) // factory {x: 4}
console.log(obj) // Object {x: 3, name: "obj"},構造函數綁定的優先級高於bind的顯式綁定

能夠見得,優先級從高到低:

  1. new,構造綁定

  2. bind,顯式綁定

  3. call/apply,顯示綁定

  4. 做爲方法綁定

  5. 默認綁定

相關文章
相關標籤/搜索