this指向哪?

谁调用就指向谁

this 指向哪?先记住一句话:谁调用就指向谁,记住这句话就成功一大半了。

js 复制代码
var userName = '张三'
function fn() {
    var userName = '李四'
    console.log(this.userName) // 张三
}
fn()

函数fn相当于挂在window,调用fn()等同于window.fn(),所以fn可以看做是被window调用,此时this便指向window,所以输出结果是函数外的userName变量。

再看下面的示例:

js 复制代码
var userName = '张三'
var obj = {
    userName: '李四',
    fn: function() {
        console.log(this.userName) // 李四
    }
}

obj.fn()

函数fn被定义在对象obj里,通过obj.fn()调用,回到我们开头的那句话:谁调用就指向谁fnobj调用,所以this指向obj,输出结果是李四。

如果使用windowd.obj.fn()调用呢?结果还是一样的,因为最终是obj调用,所以this指向的还是obj

接着往下看下面这段代码:

js 复制代码
var userName = '张三'
var obj = {
    userName: '李四',
    fn: function() {
        console.log(this.name) // 张三
    }
}

var func = obj.fn
func()

输出结果为张三,因为代码中只是将obj.fn赋值给func,此时函数fn还没有被调用,真正调用是在func()func挂在window下,所以最终相当于是window调用了函数fn,所以this指向的是window

还是应了那句话:谁调用就指向谁

其他情况

1、作为一个函数被直接调用

当函数被直接调用,没有挂在任何对象上时,this指向window

js 复制代码
var userName = '张三'
var obj = {
    userName: '李四',
    fn: function() {
        function a() {
            console.log(this.userName) // 张三
        }
        a()
    }
}
obj.fn()

这里在fn中定义了一个函数a并调用,注意这里函数a只是在函数fn内,它并没有挂在哪个对象上,也没有通过其他方式被调用,而是作为一个函数被直接调用,所以this指向window

2、箭头函数

箭头函数的特点是没有自己的this也不能通过new调用。箭头函数通过作用域向上查找,找到离包裹它最近的那一个普通函数的this作为自己的this,如果没有则指向全局对象window

js 复制代码
var userName = '张三'
var obj = {
    userName: '李四',
    fn: function() {
        var func = () => {
            console.log(this.userName) // 李四
        }
        func()
    },
    a: {
        b: () => {
            console.log(this.userName) // 张三
        }
    }
}
obj.fn()
obj.a.b()

func是一个箭头函数,箭头函数通过向上查找找到fnfnthis指向obj,所以箭头函数的this指向的也是obj,输出结果:李四。

obj.a.b()则指向window,输出结果:张三。

3、new 构造函数

当函数通过使用new调用时,new过程中会创建一个新的对象,而this便是指向这个新创建的对象。

js 复制代码
function fn(name) {
    this.userName = name
    this.age = 18
    console.log(this) // {userName: '张三', age: 18}
}
let data = new fn('张三')
// new的同时内部会默认把this做回返回值返回
console.log('data: ', data) // data: {userName: '张三', age: 18}

如何改变this指向

1、call、apply、bind

可以通过callapplybind的第一个参数传值作为this值,改变this指向。

js 复制代码
obj.fn('hello') // hello,张三
obj.fn.call({ userName: '李四' }, 'hello') // hello,李四
obj.fn.apply({ userName: '王五' }, ['hello']) // hello,王五
obj.fn.bind({ userName: '老六' }, 'hello')() // hello,老六

2、call、apply、bind区别

从上面的使用可以看到,这三个API的参数形式除了第一个参数外是有一些区别的

  • callbind是多参数的形式:call(thisArg, arg1, arg2...)
  • apply是数组的形式:call(thisArg, [arg1, arg2...])

另外一个区别是:bind的返回值是一个函数,需要自己再手动调用一次,而callapply则不用。

相关推荐
独立开阀者_FwtCoder几秒前
"页面白屏了?别慌!前端工程师必备的排查技巧和面试攻略"
java·前端·javascript
Hilaku8 分钟前
说实话,React的开发体验,已经被Vue甩开几条街了
前端·javascript·vue.js
星语卿8 分钟前
Js事件循环
javascript
datagear9 分钟前
如何在DataGear 5.4.1 中快速制作HTTP数据源服务端分页的数据表格看板
javascript·数据可视化
顾林海10 分钟前
ViewModel 销毁时机详解
android·面试·android jetpack
namehu17 分钟前
“什么?视频又双叒叕不能播了!”—— 移动端视频兼容性填坑指南
javascript·html
多啦C梦a19 分钟前
React Hooks 编程:`useState` 和 `useEffect`,再不懂就OUT了!
前端·javascript
bo5210020 分钟前
解决跨域的几种种方法, 你都知道几种?
前端·面试·浏览器
yvvvy33 分钟前
# React Hooks 全面解析:从 useState 到 useEffect,掌握状态与副作用管理
javascript
jqq66640 分钟前
Vue3脚手架实现(七、渲染eslint配置)
前端·javascript·vue.js