- this
- this的指向,是在函数被调用的时候确定的,也就是执行上下文被创建的,而不是创建时决定的。
- 调用位置:函数在代码中被调用的位置,而不是声明的位置。
(1)全局对象中的this
- this等价于widow对象
// 通过声明绑定到变量对象,但在全局环境中,变量对象就是它自身
var a1 = 10;
console.log(a1); //10
// 通过this绑定到全局对象
this.a2 = 20;
console.log(a2); //20
// 仅仅只有赋值操作,标识符会隐式绑定到全局对象
a3 = 30;
console.log(a3); //30
console.log(this === window) //true
所以 var === this. === window.
(2)函数中的this
- this由调用者提供,由调用函数的的调用方式来决定。
- 如果调用者函数,被一个对象所拥有,那么该函数在调用时,内部的this指向该对象。
- 如果函数独立调用,那么该函数内部的this,则指向undefined,非严格模式下,当this指向undefined时,它会自动指向全局对象。
例1
var a = 20;
var obj = {
a: 10,
c: this.a + 20,
fn: function () {
return this.a;
}
}
console.log(obj.c); //40 注:单独的{}对象不会形成新的作用域,所以this.a没有作用域的限制,仍处于全局
console.log(obj.fn()); //10 调用者是fn,被obj所拥有,所以this指向obj对象
例2
var a = 20;
var foo = {
a: 10,
getA: function () {
return this.a;
}
}
console.log(foo.getA()); // 10 getA是调用者,被对象foo拥有,不是独立调用,所以this指向foo
var test = foo.getA;
console.log(test()); // 20 test为调用者,这时的它是独立调用,所以this指向window(非严格模式)
例3
function foo() {
console.log(this.a)
}
function active(fn) {
fn(); // 真实调用者,为独立调用
}
var a = 20;
var obj = {
a: 10,
getA: foo
}
active(obj.getA); //active为调用者,独立调用
(3)使用call/apply指定this
- 一种可以自行手动设置this指向的机制。
- 所有的函数都具有这两种方法(非继承而来的方法),除了参数略有不同,其功能完全一样。
- 第一个参数是undefined或者null,非严格模式下,是指向window。严格模式下,就是指向第一个参数。
- call的参数是一个列表,将每个参数一个个列出来。
- apply只接受两个参数,第二个参数是一个数组或类数组,将每个参数放到一个数组中。
例1
function fn(num1, num2) {
console.log(this.a + num1 + num2);
}
var obj = {
a: 20
}
//fn并非属于对象obj的方法,但是通过call,我们将fn内部的this绑定为obj,因此就可以使用this.a访问obj的a属性了
fn.call(obj, 100, 10); // 130
fn.apply(obj, [20, 10]); // 50
例2
var name = 'window中';
var doSth = function(){
console.log(this.name);
}
var student = {
name: 'student中',
doSth: doSth,
other: {
name: 'other中',
doSth: doSth,
}
}
doSth(); // 'window中' 独立调用,this指向全局
student.doSth(); // 'student中' 被对象student所拥有,指向student对象
student.other.doSth(); // 'other中' 被other对象所拥有,指向other对象
student.doSth.call(student); // 'student中'
student.other.doSth.call(student); // 'student中' 被other所拥有,但是被call改变this指向,指向student对象
注意:通常情况下,大家会做如下处理,把对象中的函数赋值给一个变量,在进行调用,实际上这样又把该函数调用变成普通函数了,所有指向全局(非严格模式下)。
var studentDoSth = student.doSth;
studentDoSth(); // 'window中'
***参考链接:
1、前端基础进阶(七):全方位解读this/
2、面试官问:JS的this指向
(4)bind
- bind()方法主要是将函数绑定到某个对象上,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值,例如:fn.bind(obj),实际上可以理解为obj.fn(),这时,fn函数体内的this,自然指向obj。
- this将永久的被绑定到bind的第一个参数。
例1:
var a = {
b : function(){
var func = function(){
console.log(this.c);
}
func();
},
c : 'Hello!'
}
a.b(); //undefined
-------//对比上下两个例子,上面的func()属于直接调用,下面的调用者b被对象a拥有,所以this指向有差别
var a = {
b : function(){
console.log(this.c);
},
c : 'Hello!'
}
a.b(); //Hello
做简要的改造:
var a = {
b : function(){
var that = this; //可以通过赋值的方式将this赋值给that
var func = function(){
console.log(that.c);
}
func();
},
c : 'Hello!'
}
a.b(); //Hello!
通过bind的方式绑定this
var a = {
b : function(){
var func = function(){
console.log(this.c);
}.bind(this);
func();
},
c : 'Hello!'
}
a.b(); //Hello!
var a = {
b : function(){
var func = function(){
console.log(this.c);
}
func.bind(this)();
},
c : 'Hello!'
}
a.b(); //Hello!
***参考链接:JS中的bind方法
(5)箭头函数中的this
- 所有的箭头函数都没有自己的this,都指向外层。
- this指向定义时所在的对象,而不是运行时所在的对象。
箭头函数常用语回调函数中,例如定时器中:
function foo() {
setTimeout(()=>{
console.log(this.a);
},100)
}
var obj = {
a: 2
}
foo.call(obj); //2