前言
本文将从如下几点展开:
this在不同调用方式下的指向?
改变函数this的指向的apply、call如何使用?
new关键字?
箭头函数this指向?
如何确定this的指向
this的指向是在运行时确定的,js中没有动态作用域,因为this的存在,让js有了动态作用域的表现。
- 根据函数的调用对象判断
this指向最后调用的那个对象,this和在定义的位置没有关系,只 和调用的对象有关。如果没有调用者默认this指向window。
- this指向new出来的对象
为什么this指向new出来的对象呢?new的原理是什么呢?
- this指向apply、call的第一参数
案例练习:
1、this指向函数的最后的调用者
例子1:
var innerHtml = 'windowstring'
function fn() {
console.log(this.innerHtml)
}
var obj = {
innerHtml: 'objstring',
fn: fn
}
obj.fn = fn
obj.fn() //'objstring'
fn()//'windowstring'
例子2:
var x = 10;
var obj = {
x: 20,
f: function(){
console.log(this.x);
} };
obj.f(); // obj.f.call(obj) // ==> 20
var fOut = obj.f;
fOut(); // fOut.call(window) //==> 10
var obj2 = { x: 30, f: obj.f } obj2.f(); // obj2.f.call(obj2) //==> 30
例子3:
this是在运行时确定的。
以下是访问了this对象中不存在的变量和方法的2个例子:
var name = "windowsName";
var a = {
// name: "Cherry",
fn : function () {
console.log(this.name); // undefined
}
}
window.a.fn();
函数执行没有明确的调用者时,函数this都指向window:
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
},100);
}
};
a.func2() // this.func1 is not a function
2、this指向new出来的对象
3、this指向call、apply的第一个参数
设置this指向特定对象的方法
1.箭头函数2.apply、call、bind
3.函数内部保存this
使用箭头函数:
箭头函数,不会创建自己的this,它从其作用域链的上一层继承。
function Person(){
this.age = 0;
(() => {
this.age = 30;
setInterval(() => {
this.age++; // |this| 正确地指向 p 实例
console.log(this.age)
}, 1000);
})()
}
var p = new Person();
箭头函数与Es5函数的不同:
1、严格模式下,箭头函数this指向全局对象,普通函数this指向undefined。
2、箭头函数没有arguments。
3、箭头函数没有prototype属性。
4、箭头函数的this没有普通函数this的规则:
- 不能使用new关键词,不能作为构造函数。
- this不会指向函数的调用者。
- apply/call的第一个参数会被忽略。
这也是为什么vue中methods中函数不能用箭头函数的原因,箭头函数中会拿不到vue的实例,vue中函数绑定vue实例是通过函数的apply方法。
(注意:箭头函数也可以创建闭包。)
案例实践:
例子1:
var adder = {
base : 1,
add : function(a) {
var f = v => v + this.base;
return f(a);
},
addThruCall: function(a) {
var f = v => v + this.base;
var b = {
base : 2
};
return f.call(b, a);
}
};
console.log(adder.add(1)); // 输出 2
console.log(adder.addThruCall(1)); // 仍然输出 2
例子2:
var name = 'bob'
var obj = {
name: 'alice',
showName: () => {
console.log(this.name)
}
}
obj.showName()
例子3:
function getValue(value) {
this.name = '4444'
var b = bb=> {
var f = v => this.name + v;
var obj = {
name: 'youyi',
};
return f.call(obj, value);
}
return b()
}
console.log(getValue( 'is fine')) //4444is fine
例子4:
var adder = {
base : 1,
add : function(a) {
var b = vv => {
var f = v => v + this.base;
return f(a);
}
return b()
},
addThruCall: function(a) {
var f = v => v + this.base;
var b = {
base : 2
};
return f.call(b, a);
}
};
console.log(adder.add(1)); // 输出 2
console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3)
例子5:
var adder = {
base : 1,
add : function(a) {
function b() {
var f = v => v + this.base;
return f(a);
}
return b()
},
addThruCall: function(a) {
var f = v => v + this.base;
var b = {
base : 2
};
return f.call(b, a);
}
};
console.log(adder.add(1)); // 输出 NaN
console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3)
this经典题目
例子1:
var a=10;
var foo={
a:20,
bar:function(){
var a=30;
console.log(this)
return this.a;
}
};
foo.bar()
(foo.bar)()
(foo.bar=foo.bar)()
(foo.bar,foo.bar)()
例子2:
function t(){
this.x=2;
}
t();
console.log(window.x);
例子3:
var obj = {
x: 1,
y: 2,
t: function() {
console.log(this.x)
}
}
obj.t();
var dog={x:11};
dog.t=obj.t;
dog.t();
show=function(){
console.log('show'+this.x);
}
dog.t=show;
dog.t();
例子4:
name = 'this is window';
var obj1 = {
name: 'php',
t: function() {
console.log(this.name)
}
};
var dog1 = {
name: 'huzi'
};
obj1.t();
dog1.t = obj1.t;
var tmp = dog1.t;
tmp(); //this本来指向window
(dog1.t = obj1.t)(); //'huzi' 对比1题中的(foo.bar=foo.bar)()
dog1.t.call(obj1);
例子5:
var number=2;
var obj={
number:4,
/*匿名函数自调*/
fn1:(function(){
var number;
this.number*=2;//4 8
number=number*2;//NaN
number=3;
return function(){
var num=this.number;
this.number*=2;// 8 8
console.log('0000000...',num); //4 4
number*=3;//9
console.log('222222...',number);//9 27
}
})(),
db2:function(){
this.number*=2;
}
}
var fn1=obj.fn1;
console.log('11111111:',number);//4
fn1();
obj.fn1();
console.log('window:',window.number);//8
console.log('obj:',obj.number);//8 易错点
参考资料:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。