javascript中this的指向问题
使用 JavaScript 开发的时候,很多开发者多多少少会被 this
的指向搞蒙圈,但是实际上,关于 this
的指向,记住最核心的一句话:
哪个对象调用函数,函数里面的this指向哪个对象。
分几种情况谈论下:
一、普通函数调用
二、对象函数调用
三、构造函数调用
四、apply和call调用
五、箭头函数调用
文章同步交流社区地址:http://www.mwcxs.top/page/427.html
一、普通函数调用
这个情况没特殊意外,就是指向全局对象-window。
1、使用let
/*普通函数调用*/ let username = "程新松"; function fn(){ console.log(this.username); //undefined } fn();
使用node输出的是:undefined
使用谷歌浏览器console输出的是:undefined
2、使用var
var name = "程新松"; function fn(){ console.log(this.name); } fn();
使用node输出的是:undefined
使用谷歌浏览器console输出的是:程新松
3、使用window
window.username='程新松' function fn(){ console.log(this.username); } fn();
使用node输出的是:报错,window没有定义
使用谷歌浏览器console输出的是:
PS:为什么会出现这个错误呢,因为node里面没有window 对象,浏览器中有window对象。
4、let和var区别:
(1)let
允许把变量的作用域限制在块级域中;var 申明变量要么是全局的,要么是函数级的,而无法是块级的。
let varClass = function(){ var name='程新松'; if(true){ var name='saucxs'; console.log(name); } console.log(name); } varClass(); // saucxs // saucxs
let letClass = function(){ let name='程新松'; if(true){ let name='saucxs'; console.log(name); } console.log(name); } letClass();
上面的结果说明了let只在{}内使用。
(2)先let后var
let subClass = function(){ let name='程新松'; if(true){ var name='saucxs'; console.log(name); } console.log(name); } subClass();
var 是函数级作用域,相当于一个作用域中有两个n的变量了
var 作用于整个 subClass ,和let冲突了,let不能重复声明,already been declared=已经被声明
(3)先var后let
let subClass = function(){ var name='程新松'; if(true){ let name='saucxs'; console.log(name); } console.log(name); } subClass();
先申明var,再申明let,这个没有问题。
二、对象函数调用
这个相信不难理解,就是哪个函数调用,this指向哪里。
/*对象函数调用*/ //window.name='程新松'; //var name='程新松'; let name='程新松'; let obj={ id:201102304, fn:function(){ console.log(this.name); //undefined console.log(this.id); //201102304 } } obj.fn();
,,
很明显,第一次就是输出 obj.name
,但是没有这个name属性,输出的结果undefined。而第二次输出obj.id,有这个id属性,
输出 201102304,因为 this
指向 obj
。
有一种情况需要注意:
/*需要注意的情况*/ let obj1={ a:111 } let obj2={ a:222, fn:function(){ console.log(this.a); } } obj1.fn=obj2.fn; obj1.fn(); //111
这个也不难理解,虽然 obj1.fn
是从 obj2.fn
赋值而来,但是调用函数的是 obj1
,所以 this
指向 obj1
。
三、构造函数调用
/*构造函数调用*/ let structureClass=function(){ this.name='程新松'; } let subClass1=new structureClass(); console.log(subClass1.name); let subClass=new structureClass(); subClass.name='成才'; console.log(subClass.name);
但是有一个坑,虽然一般不会出现,但是有必要提一下。
在构造函数里面返回一个对象,会直接返回这个对象,而不是执行构造函数后创建的对象
let structureClass=function(){ this.name='程新松'; return { username:'saucxs' } } let subClass1=new structureClass(); console.log(subClass1); console.log(subClass1.name);
四、apply和call调用
1、apply和call简单来说就是会改变传入函数的this。
/*apply和call调用*/ let obj1={ name:'程新松' }; let obj2={ name:'saucxs', fn:function(){ console.log(this.name); } } obj2.fn.call(obj1);
此时虽然是 obj2
调用方法,但是使用 了 call
,动态的把 this
指向到 obj1
。相当于这个 obj2.fn
这个执行环境是 obj1
。
call
和 apply
两个主要用途:
1.改变 this
的指向(把 this
从 obj2
指向到 obj1
)
2.方法借用( obj1
没有 fn
,只是借用 obj2
方法)
2、call与apply区别
call
和 apply
的作用,完全一样,唯一的区别就是在参数上面。
call
接收的参数不固定,第一个参数是函数体内 this
的指向,第二个参数以下是依次传入的参数。
apply接收两个参数,第一个参数也是函数体内 this
的指向。第二个参数是一个集合对象(数组或者类数组)
/*apply和call区别*/ let fn=function(a,b,c){ console.log(a,b,c); } let arrArray=[1,2,3]; fn.call(window,arrArray); fn.apply(window,arrArray);
五、箭头函数调用
首先不得不说,ES6 提供了箭头函数,增加了我们的开发效率,但是在箭头函数里面,没有 this
,箭头函数里面的 this
是继承外面的环境。
/*箭头函数调用*/ let obj={ name:'程新松', fn:function(){ setTimeout(function(){console.log(this.name)}) } } obj.fn();
不难发现,虽然 fn() 里面的 this 是指向 obj ,但是,传给 setTimeout 的是普通函数, this 指向是 window , window 下面没有 name ,所以这里输出 underfind 。
换成箭头函数
//换成箭头函数 let obj={ name:"程新松", fn:function(){ setTimeout(()=>{console.log(this.name)}); } } obj.fn();
这次输出 程新松 是因为,传给 setTimeout 的是箭头函数,然后箭头函数里面没有 this ,所以要向上层作用域查找,在这个例子上, setTimeout 的上层作用域是 fn 。而 fn 里面的 this 指向 obj ,所以 setTimeout 里面的箭头函数的 this ,指向 obj 。所以输出 程新松。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
2016-04-02 软件工程 Android小游戏 猜拳大战