关于前端:JavaScript-内的-this-指向

5次阅读

共计 5407 个字符,预计需要花费 14 分钟才能阅读完成。

在 javascript 语言中, 有一个奇奇怪怪的 “ 关键字 ” 叫做 this 为什么说它是 奇奇怪怪 呢, 是因为你写出 100 个 this, 可能有 100 个解释, 齐全不挨边,然而, 在你的学习过程中, 搞清楚了 this 这个玩意, 那么会对你的开发生涯有很大帮忙的,接下来咱们就开始一点一点的认识一下 this

this 初意识

看到 this, 先给他翻译过去 “ 这个 ” 到底啥意思呢 ?

饭桌上, 你妈和你说, 你多吃点的这个

商店里, 你媳妇和你说, 这个包 这个包 这个包 我都要

宴会上, 你爸和人介绍说, 这个傻小子是我儿子

你看, 每一句话上都有 “ 这个 ”, 然而每个 “ 这个 ” 都是一个意思吗? 并不,就像咱们 js 内的 this 一样, 每一个 this 的意思都不一样,然而咱们会发现,在谈话的过程中, “ 这个 ” 是和咱们谈话的手势有关系在 js 内一个情理,this 的意思是和代码的 “ 手势 ” 有关系例子 :

当你媳妇手指着一个 LV 包的时候, 说的 “ 这个 ” 指代的就是 LV 包

当你妈指着鱼香肉丝的时候说 “ 这个 ” 指代的就是 鱼香肉丝

所以在 javascript 内的 this 是要看 “ 说这句话的代码手指向哪里了 ”

看看上面一段代码

var box = document.querySelector('#box')

box.onclick = function () {console.log(this)
}

当你点击 box 这个元素的时候, 会触发前面的函数, 而后函数一执行, 就会在控制台打印一下 this, 这里的 this 就是 box 这个元素, 这就是一个非常简单的 this 指向的例子了

接下来咱们就开始具体学习一下 this

给你个概念 , this , 是一个指针形变量, 它动静的指向以后函数的运行环境,” 什么鬼货色, 我听不懂啊 ”, 给一个私人的解释 : “ 依据 this 所在的函数是如何被调用的来决定 this 是什么 ”

举个例子来看一下

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

// this 就是 window

因为 this 是在 fn 函数内, 所以 fn 函数的调用形式就决定了这个 this 是什么

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

// this 就是 window

因为 this 是在 b 函数内, 所以 b 函数的调用形式决定了 this 是什么, 和 a 函数没关系, 就是这个意思, 最初, 依据这些年的经验总结给出一个私人的概念, 要牢记

函数的 this

和函数定义在哪没关系

和函数怎么定义没关系

只看这个函数的调用形式

箭头函数除外

对象调用对象调用, 就是利用一个对象作为宿主来调用函数最简略的形式就是把函数写在一个对象内, 利用对象来调用

// 对象内写一个函数
const obj = {fn: function () {console.log(this) }
}

// 调用这个函数
obj.fn()

这时候, 咱们调用了和这个对象内的 fn 函数

调用形式就是利用对象调用的函数, 所以在这个函数内的 this 就是 obj 这个对象, 换句话说, 只有在这个函数内, 只有呈现 this 就是这个对象

全局调用

顾名思义, 全局调用就是间接调用一个全局函数

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

fn()

此时这个函数内的 this 就是 window, 可能有的小伙伴感觉疯了, 然而咱们认真思考一下, 你会发现, 其实 fn 因为是在全局上的, 那么其实调用的残缺写法能够写成 window.fn(), 此时就回到了之前对象调用那条路上, 这样就通顺了

奇怪的调用

这个时候, 有的小伙伴可能会想到一个问题, 如果这个函数不放在全局呢 ?

const obj = {fn: function () {function fun() {console.log(this)
        }

        fun()}
}

obj.fn()

此时的 this 应该是什么呢 ?

依照之前的思路思考,○ obj.fn() 的确调用了函数, 然而 this 不是在 obj.fn 函数内, 是在 fun 函数内,○ fun() 的确也调用了函数, 然而我没有方法写成 window.fun(),○ 那么 this 到底是不是 window 呢, 还是应该是 obj 内

答案的确是 window, 这又是为什么呢 ?

捋一下思路

说到这里, 咱们会发现,this 真的是好奇怪哦 o(~︶~)o 搞不定了, 要是依照这个形式, 我来回来去的得记多少种, 谁会记得下来呢

接下来(划重点)

我用写代码三十年的教训给你总结进去了一些内容, 心愿你能牢记

this 的集体教训

首先, this 在各种不同的状况下会不一样, 那么从当初开始我把我总结的内容毫无保留的传授给你

教训一 :

在 js 的非严格模式下实用

在非箭头函数中实用

不论函数定义在哪, 不论函数怎么定义, 只看函数的调用形式

只有我想晓得 this 是谁

就看这个 this 是写在哪个函数外面

这个函数是怎么被调用的

察看 this 在哪个函数内

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

// this 在函数 fn 内, 就看 fn 函数是怎么被调用的就能晓得 this 是谁
const obj = {fn: function () {console.log(this)
    }
}

// this 在 obj.fn 函数内, 就看这个函数怎么被调用的就能晓得 this 是谁
const obj = {fn: function () {function fun() {console.log(this)
        }
    }
}

// 这个 this 是在 fun 函数内
// 如果你想晓得这个 this 是谁
// 和 obj.fn 函数没有关系, 只有晓得 fun 函数是怎么被调用的就能够了

肯定要留神 : 你想晓得的 this 在哪个函数内, 就去察看哪个函数的调用形式就好了一些常见的函数调用形式

一般调用

调用形式 : 函数名 ()
this 是 window
只有你书写 “ 函数名()” 调用了一个函数, 那么这个函数内的 this 就是 window

function fn() {console.log(this)
}
fn()
// 这里就是 fn() 调用了一个函数, 那么 fn 内的 this 就是 window
const obj = {fn: function () {function fun() {console.log(this)
        }
        fun()}
}
obj.fn()
// 这里的 this 因为是在 fun 函数内
// fun() 就调用了这个 fun 函数
// 所以不必管 fun 函数写在了哪里
// 这个 fun 函数内的 this 就是 window

2,对象调用

调用形式:

对象. 函数名()

对象 ’ 函数名 ’

this 就是这个对象, 对象叫啥, 函数内的 this 就叫啥

const obj = {fn: function () {console.log(this)
    }
}
obj.fn()
// 因为 obj.fn() 调用了这个函数, 所以 obj.fn 函数内的 this 就是 obj
const xhl = {fn: function () {console.log(this)
    }
}
xhl.fn()
// 因为 obj.fn() 调用了这个函数, 所以 xhl.fn 函数内的 this 就是 xhl
function fn() {
    const xhl = {fn: function () {console.log(this)
        }
    }
    xhl.fn()}

fn()
// 因为咱们要察看的 this 是在 xhl.fn 这个函数内
// 所以只须要关注这个函数是如何被调用的即可
// 因为是 xhl.fn 调用了和这个函数, 所以函数内的 this 就是 xhl

3,定时器调用

调用形式

setTimeout(function () {}, 1000)

setInterval(function () {}, 1000)

this 就是 window

一个函数不论是怎么定义的, 只有被当做定时器处理函数应用, this 就是 widnow

setTimeout(function () {console.log(this)
}, 1000)
// 这里的 this 就是 window
setInterval(function () {console.log(this)
}, 1000)
// 这里的 this 就是 window
const xhl = {fn: function () {console.log(this)
    }
}

setTimeout(xhl.fn, 1000)
// 这里的 xhl.fn 函数不是间接书写 xhl.fn() 调用的
// 而是给到了 setTimeout 定时器处理函数
// 所以这里的 this 就是 window

4,事件处理函数

调用形式

事件源.on 事件类型 = 事件处理函数

事件源.addEventListener(事件类型, 事件处理函数)

this 就是 事件源

只有是作为事件处理函数应用, 那么该函数内的 this 就是 事件源奥,对了,事件就是:在事件中,以后操作的那个元素就是事件源

box.onclick = function () {console.log(this)
}
// 这里的 this 就是 box
box.addEventListener('click', function () {console.log(this)
})
// 这里的 this 就是 box
const xhl = {fn: function () {console.log(this)
    }
}

box.addEventListener('click', xhl.fn)
// 这里的 xhl.fn 函数不是间接书写 xhl.fn() 调用的
// 而是给到了 事件, 被当做了事件处理函数应用
// 所以这里的 this 就是 事件源 box
const xhl = {fn: function () {console.log(this)
    }
}

box.onclick = xhl.fn
// 这里的 xhl.fn 函数不是间接书写 xhl.fn() 调用的
// 而是给到了 事件, 被当做了事件处理函数应用
// 所以这里的 this 就是 事件源 box

5,结构函数调用

调用形式

new 函数名()

this 就是该构造函数的以后实例

只有和 new 关键字调用了, this 就是实例对象

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

const f = new fn()
// 这里的因为 fn 函数和 new 关键字在一起了
// 所以这里的 this 就是 fn 函数的实例对象
// 也就是 f
const xhl = {fn: function () {console.log(this)
    }
}

const x = new xhl.fn()
// 这里的 xhl.fn 也是因为和 new 关键字在一起了
// 所以这里的 this 就是 xhl.fn 函数的实例对象
// 也就是 x

记分明准则 :

不论函数在哪定义, 不论函数怎么定义, 只看函数的调用形式

教训二 :

在严格模式下实用, 其实只有一个, 全局函数没有 this, 是 undefined, 其余的照搬教训一就能够了

1,非严格模式

// 非严格模式
function fn() {console.log(this)
}
fn()
// 因为是在非严格模式下, 这里的 this 就是 window

2. 严格模式

// 严格模式
'use strict'
function fn() {console.log(this)
}
fn()
// 因为是在严格模式下, 这里的 this 就是 undefined

记分明准则 :

严格模式下, 全局函数没有 this, 是个 undefiend

教训三 :

专门来说一下箭头函数, 其实也只有一条

颠覆之前的所有内容, 箭头函数内没有本人的 this, 箭头函数内的 this 就是内部作用域的 this

换句话说, 当你须要判断箭头函数内的 this 的时候, 和函数怎么调用没有关系了, 要看函数定义在什么地位

// 非箭头函数
const xhl = {fn: function () {console.log(this)
    }
}
xhl.fn()
// 因为是 非箭头函数, 所以这里的 this 就是 xhl

// ==========================================================

// 箭头函数
const xhl = {fn: () => {console.log(this)
    }
}
xhl.fn()
// 因为是 箭头函数, 之前的教训不实用了
// 这个函数内部其实就是全局了, 所以这里的 this 就是 window
// 非箭头函数
box.onclick = function () {console.log(this)
}
// 因为是 非箭头函数, 这里的 this 就是 box

// ==========================================================

// 箭头函数
box.onclick = () => {console.log(this)
}
// 因为是 箭头函数
// 这个函数内部就是全局了, 所以这里的 this 就是 window
// 非箭头函数
const obj = {fn: function () {function fun() {console.log(this)
        }
        fun()}
}
obj.fn()
// 因为是 非箭头函数, 所以 fun 函数内的 this 就是 window

// ==========================================================

// 箭头函数
const obj = {fn: function () {const fun = () => {console.log(this)
        }
        fun()}
}
obj.fn()
// 因为是 箭头函数
// 那么这个 fun 里面其实就是 obj.fn 函数
// 所以只有晓得了 obj.fn 函数内的 this 是谁, 那么 fun 函数内的 this 就进去了
// 又因为 obj.fn 函数内的 this 是 obj
// 所以 fun 函数内的 this 就是 obj

记分明准则 :

只有是箭头函数, 不论函数怎么调用, 就看这个函数定义在了哪里

最初

好了, 依照以上三个教训, 记分明准则, 那么在看到 this 就不慌了

正文完
 0