avatar

目录
this的指向

this的指向

在先看文章前,看看能不能把这些题给做出来

javascript
1
2
3
4
5
6
7
8
9
var obj = {
foo: function(){
console.log(this)
}
}

var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window

函数调用

JS(ES5)里面有三种函数调用形式

Code
1
2
3
fun()	// 直接调用
obj.fun() // 对象调用
fun.call(context,p1,p2)

一般,初学者都知道前两种形式,而且认为前两种形式「优于」第三种形式。

从看到这篇文章起,你一定要记住,第三种调用形式,才是正常调用形式:

Code
1
func.call(context, p1, p2)

其他两种都是语法糖,可以等价地变为 call 形式:

Code
1
2
3
4
5
func(p1, p2) 等价于
func.call(undefined, p1, p2)

obj.child.method(p1, p2) 等价于
obj.child.method.call(obj.child, p1, p2)

至此我们的函数调用只有一种形式:

Code
1
func.call(context, p1, p2)

这样,this 就好解释了

this,就是上面代码中的 context。就这么简单。

this 是你 call 一个函数时传的 context,由于你从来不用 call 形式的函数调用,所以你一直不知道。

先看 func(p1, p2) 中的 this 如何确定:

当你写下面代码时

Code
1
2
3
4
5
function func(){
console.log(this)
}

func()

用「转换代码」把它转化一下,得到

Code
1
2
3
4
5
function func(){
console.log(this)
}

func.call(undefined) // 可以简写为 func.call()

按理说打印出来的 this 应该就是 undefined 了吧,但是浏览器里有一条规则:

如果你传的 context 是 null 或 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)

因此上面的打印结果是 window。

如果你希望这里的 this 不是 window,很简单:

Code
1
func.call(obj) // 那么里面的 this 就是 obj 对象了

再看 obj.child.method(p1, p2) 的 this 如何确定

Code
1
2
3
4
5
6
7
var obj = {
foo: function(){
console.log(this)
}
}

obj.foo()

按照「转换代码」,我们将 obj.foo() 转换为

Code
1
obj.foo.call(obj)

好了,this 就是 obj。搞定。

回到题目:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
var obj = {
foo: function(){
console.log(this)
}
}

var bar = obj.foo
obj.foo() // 转换为 obj.foo.call(obj),this 就是 obj
bar()
// 转换为 bar.call()
// 由于没有传 context
// 所以 this 就是 undefined
// 最后浏览器给你一个默认的 this —— window 对象

[ ] 语法

Javascript
1
2
3
function fn (){ console.log(this) }
var arr = [fn, fn2]
arr[0]() // 这里面的 this 又是什么呢?

我们可以把 arr0 想象为arr.0( ),虽然后者的语法错了,但是形式与转换代码里的 obj.child.method(p1, p2) 对应上了,于是就可以愉快的转换了:

Javascript
1
2
3
4
        arr[0]() 
假想为 arr.0()
然后转换为 arr.0.call(arr)
那么里面的 this 就是 arr 了 :)

Node-this的指向区别

由于NodeJs的运行环境不一样,完全脱离了浏览器,所以它的this不是指向window

javascript
1
2
3
4
5
function fun(){
console.log(this);
}

fun() // global

use strict

在严格模式下,this将保持他进入执行环境时的值,所以下面的this将会默认为undefined

所以,在严格模式下,如果 this 没有被执行环境(execution context)定义,那它将保持为 undefined

Bom和Node环境下都是一样的

javascript
1
2
3
4
5
6
function f2(){
"use strict";
return this;
}

f2() === undefined; // true

修改this的指向

通过ES6的箭头函数修改

Code
1
2
3
4
5
6
7
8
9
10
11
document.querySelector("#app").onclick = function () {
function aa() { console.log(this); }
let bb = ()=>{ console.log(this); }
aa(); // window
bb(); // app
}


解析:
aa 是被window所调用
bb 由于箭头函数,所以this被指指向了事件的调用者

通过bind的修改

  1. bind的作用:为前面的函数,修改函数内部的this指向,让函数内部的this,指向bind的参数列表中的第一个参数

  2. 注意:bind中的第一个参数,是用来修改this指向的,第一个参数后面的所有参数,都会当作将来调用前面函数时候的参数传递进去

  3. bind并不会修改原函数,bind的函数会将改变了this指向的原函数作为返回值

  4. bind和call/apply之间的区别

    • call/apply修改完this指向后,会立即调用前面的函数,但是bind只是修改this指向,并不会调用
  5. 用法

    Code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    function ww(){
    conosle.log(this);
    }

    ww(); // window

    document.getElementById("app").onclick = function(){
    console.log(this); // app

    ww = ww.bind(this);
    }

    ww(); // app
  6. 使用方式

    1. 在事件处理函数中,直接使用bind绑定this并传参
    2. 绑定函数并接收返回值

apply

call

作为对象的方法

Code
1
2
3
4
5
6
7
8
var o = {
props: 12,
fun: function(){
return this.props
}
}

console.log(o.fun()) // 12
文章作者: 青空
文章链接: https://gitee.com/AIR-ZRB/blog/2020/03/02/JavaScript-this%E7%9A%84%E6%8C%87%E5%90%91/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 青空
打赏
  • 微信
    微信
  • 支付寶
    支付寶