浅谈js的this指向问题
Posted qncsssznds
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈js的this指向问题相关的知识,希望对你有一定的参考价值。
javascript里函数的this指向,是一个挺难弄清楚的问题。网上大佬们的总结是:
哪个对象调用函数,函数里面的this就默认指向哪个对象。(注意this指向的只能是对象)
我个人把这句话理解成:看它函数名后加小括号时它的前缀是什么。
为什么说“默认指向”?因为JavaScript给我们提供了几种可以改变函数this指向的方法bind、call和apply。
接下来我们分别举几种常见情况来帮助理解this的默认指向。
一、全局作用域的函数中,this默认指向全局对象window。
如下,函数fn加小括号时它没有前缀,这时对它的调用fn()其实相当于window.fn(),所以this指向的是window。
function fn(){
console.log(this);//window
}
fn();
但是这种情况在严格模式时有些不同
严格模式下,一般函数调用(不是对象的方法调用,也不使用apply/call/bind等修改this),this指向undefined,而不是全局对象。这是严格模式所规定的。
function fo(){
‘use strict‘
console.log(this);//undefined
}
fo();
二、对象里的函数,this指向该对象。
如下,函数fn的属于对象obj的属性:
var obj = {
a:1,
fn:function(){
console.log(this);
}
}
obj.fn();//obj
可以看到,调用fn时它的前缀是obj,所以它的this指向对象obj。
我们来看一种复杂的:
先声明一个全局作用域下的方法fn,它的功能是输出自己的this,在声明对象obj1和obj2,obj1里声明一个属性fn1,其功能与fn相同,obj2里也声明的属性fn2,除了和fn相同的功能外,fn2还调用了fn和fn1。
function fn(){
console.log(this);
}
var obj1 = {
a: 1,
fn1: function () {
console.log(this);
}
}
var obj2 = {
a: 2,
fn2: function () {
fn();
obj1.fn1();
console.log(this);
}
}
obj2.fn2();
我们在全局下调用fn2,其结果为:
//Window
//Object { a: 1, fn1: fn1() }
//Object { a: 2, fn2: fn2() }
由结果分析:
- fn() => Window.fn(),前缀为Window,fn的this则指向Window;
- obj1.fn1(),前缀为obj1,fn1的this则指向obj1;
- obj2.fn2(),前缀为obj2,fn2的this则指向obj2;
三、函数作为Window内置函数的回调函数调用
此时该this指向window( setInterval setTimeout 等)
var timer =null;
timer = setInterval(function(){
console.log(this);
},1000);
四、箭头函数的this指向存在差异:
箭头函数的this是上一层上下文的this。
箭头函数的this指向在声明函数的时候就固定了,终身不变。
箭头函数时ES6中的内容,本人了解的还不够多,这里就先不赘述了。
五、更改this指向的方法:
1、call
call方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向。
语法: 函数名.call(要改变的 this 指向,要给函数传递的参数1,要给函数传递的参数2, ...)
var obj = { name: ‘Jack‘ }
function fn(a, b) {
console.log(this)
console.log(a)
console.log(b)
}
fn(1, 2)
fn.call(obj, 1, 2)
- fn() 的时候,函数内部的 this 指向 window
- fn.call(obj, 1, 2) 的时候,函数内部的 this 就指向了 obj 这个对象
- 使用 call 方法的时候:
- 会立即执行函数
- 第一个参数是你要改变的函数内部的 this 指向
- 第二个参数开始,依次是向函数传递参数
2、apply
apply方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向。
语法: 函数名.apply(要改变的 this 指向,[要给函数传递的参数1, 要给函数传递的参数2, ...])
var obj = { name: ‘Jack‘ }
function fn(a, b) {
console.log(this)
console.log(a)
console.log(b)
}
fn(1, 2)
fn.call(obj, [1, 2])
- fn() 的时候,函数内部的 this 指向 window
- fn.apply(obj, [1, 2]) 的时候,函数内部的 this 就指向了 obj 这个对象
- 使用 apply 方法的时候:
- 会立即执行函数
- 第一个参数是你要改变的函数内部的 this 指向
- 第二个参数是一个 数组,数组里面的每一项依次是向函数传递的参数
3、bind
bind方法是把获取到的函数重新封装,返回一个新的函数地址。新地址的this指向改变。
语法:函数.bind(要改变的 this 指向, bind传递的参数1, bind传递参数2, ...);
function fo(a, b){
console.log(this, a, b);
}
var poo = fo.bind( {a : 1} );
console.log(poo)// ? fo(a, b) { console.log(this, a, b); }
- bind绑定的this指向,无法被call和apply更改。
- 对新返回的函数传递参数,其参数是顺延在bind传递的参数之后的,即bind参数优先。
- 使用bind方法的时候:
- 不能再具名函数声明时直接使用bind
- 可以在赋值式函数声明时直接使用bind
- 可以在具名函数声明之后使用bind
- 函数只有一个函数,包装之后使用的还是这个函数
bind、call和apply的不同之处:
- call有多个参数,第一个参数表示要改变的 this 指向,其余参数对应要给函数传递的参数。
- apply只有两个参数,第一个参数表示要改变的 this 指向,第二个参数表示对应要给函数传递的参数的数组。
相同之处:
- call和apply统一都是在函数调用的时候更改this指向的方法。
- bind绑定的this指向,无法被call和apply更改。
- bind 返回的是一个新的函数,你必须调用它才会被执行。
以上内容全是本人的一点拙见,如有错误,还望各位大佬指正。
以上是关于浅谈js的this指向问题的主要内容,如果未能解决你的问题,请参考以下文章