Skip to content

处理this

this是JS中最具魅惑的知识点, 不同的应用场合, this的取值可能会有意想不到的结果, 在此我们以往都是根据**this默认的取值**的情况下, 进行的归纳和总结

这篇文档, 我们就来专门写写this(这里同一在浏览器环境下)

this指向

普通函数

普通函数的调用方式决定了this的值, 也就是谁调用的, this就指向谁

js
function Test1() {
    console.log(this)
    // window
}
Test1()

const Test2 = function () {
    console.log(this)
    // window
}
Test2()

const Obj = {
    Test3: function () {
        console.log(this)
        // Object
    }
}
Obj.Test3()

document.querySelector("button").addEventListener("click", function () {
    console.log(this)
    // button
})
js
"use strict"
function Test1() {
    console.log(this)
    // undefined
}
Test1()

const Test2 = function () {
    console.log(this)
    // undefined
}
Test2()

const Obj = {
    Test3: function () {
        console.log(this)
        // Object
    }
}
Obj.Test3()

document.querySelector("button").addEventListener("click", function () {
    console.log(this)
    // button
})

普通函数没有明确调用者时this值为window, 严格模式下没有调用者时this的值为undefined

箭头函数

箭头函数中的this与普通函数完全不同, 也不受调用方式的影响, 事实上箭头函数中并不存在this

  1. 箭头函数会默认帮我们绑定外层this的值, 所以在箭头函数中this的值和外层的this是一样的
  2. 箭头函数中的this引用的就是最近作用域中的this
  3. 向外层作用域中, 一层一层查找this, 直到有this的定义
js
const Test1 = () => {
    console.log(this)
    // window
}
Test1()

const Obj = {
    Test2:  () => {
        console.log(this)
        // window
    }
}
Obj.Test2()

document.querySelector("button").addEventListener("click", () => {
    console.log(this)
    // window
})

警告

由于箭头函数的特殊性

事件回调函数里和基于原型的面向对象都不推荐使用箭头函数

改变this

JS中允许指定函数中的this指向, 共有3个方法

call

fun.call(thisArg, arg1, arg2, ...)

thisArg: 在函数运行时指向的this

arg: 传递的其他参数

返回值: 就是返回函数的返回值, 因为他就是调用函数

js
const Obj = {
    Name: "柒月"
}
function Fun(X, Y) {
    console.log(this)
    // window
    return X + Y
}

console.log(Fun.call(Obj, 2, 3))

apply

fun.apply(thisArg, argsArray)

thisArg: 在函数运行时指向的this

argsArray: 传递的其他参数, 必须用数组包着

返回值: 就是返回函数的返回值, 因为他就是调用函数

js
const Obj = {
    Name: "柒月"
}
function Fun(X, Y) {
    console.log(this)
    // window
    return X + Y
}

console.log(Fun.apply(Obj, [2, 3]))

apply主要与数组有关, 例如使用Math.max()去数组最大值

js
const Arr = [1, 5, 66, 448, 3, 114514]
const Max = Math.max.apply(Math, Arr)
const Min = Math.min.apply(Math, Arr)

console.log(Max, Min)
// 114514 1

bind

fun.bind(thisArg, arg1, arg2, ...)

thisArg: 在函数运行时指向的this

arg: 传递的其他参数

返回值: 由指定的this值和初始化参数改造的原函数拷贝(新函数)

js
const Obj = {
    Name: "柒月"
}
function Fun1(X, Y) {
    console.log(this)
    // window
    return X + Y
}

const Fun2 = Fun1.bind(Obj, 2, 3)
console.log(Fun2())

因此, 当我们只想改变this指向, 并且不想调用这个函数时, 可以使用bind, 比如改变定时器内部的this执行

例如:有一个按钮, 点击禁用, 3秒后恢复

js
const But = document.querySelector("button")
But.addEventListener("click", function () {
    // 禁用按钮
    this.disabled = true
    setTimeout(function () {
        // 在这里面, 我们要将原来的window改成button
        this.disabled = false
    }.bind(But), 3000)
})

总结

  • 相同点
    • 都可以改变函数内部的this指向
  • 区别点
    • callapply会调用函数, 并且改变函数内部this指向
    • callapply传递的参数不一样, call传递参数Aru1, Aru2...形式, apply必须数组形式[Arg]
    • **bing不会调用函数, 可以改变函数内部this指向
  • 主要应用场景
    • call调用函数并且可以传递参数
    • apply经常跟数组有关系.比如借助与数学对象实现数组最大值最小值
    • bind不调用函数, 但是还想改变this指向.比如改变定时器内部的this指向