发表于: 2017-04-15 20:32:17
0 1366
JS中this的指向
小课堂【郑州第八十二期】
分享人:王相博
1.背景介绍
在Java语言中,this关键字的含义是明确且具体的,表示当前对象。而在javascript中,this是动态绑定的,它可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。这就导致了this具备了多重含义,可以使得javascript更灵活的使用。但是,带来了灵活性的同时也会给我们初学者带来不少困惑。
2.知识剖析
全局环境中的this
console.log(this);
总结:在全局作用域中它的 this 执行当前的全局对象(浏览器端是 Window,node 中是 global)
严格模式 ‘use strict’下的this
'use strict';
function test() {
console.log(this);
};
test();
// undefined
原因:this 并不会指向全局,而是 undefined,这样的做法是为了消除 js 中一些不严谨的行为
在javascritp中,不一定只有对象方法的上下文中才有this, 全局函数调用和其他的几种不同的上下文中也有this指代。 它可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。JavaScript 中函数的调用有以下几种方式:作为对象方法调用,作为函数调用,作为构造函数调用,和使用 apply 或 call 调用。
1.作为对象方法调用:this 被自然绑定到该对象
var obj = {
name: 'qiutc',
foo: function() {
console.log(this.name);
}
}
obj.foo();
// 'qiutc'
2.作为函数调用:this被绑定到全局对象
function test() {
console.log(this);
};
test();
// Window
3.作为构造函数调用:this 绑定到新创建的对象上
function Person(name) {
this.name = name;
console.log(this);
}
var p = new Person('dawa');
// Person {name: "dawa"}
注:构造函数不使用new调用,则和普通函数一样。一般地,构造函数首字母大写
4.使用 apply 或 call 调用:在 JavaScript 中函数也是对象,对象则有方法,apply 和 call 就是函数对象的方法。
function cat(){}
cat.prototype={
name:"tom",
food:"fish",
say: function(){
console.log(this.name+" love "+this.food);
}};
var blackCat = new cat;
blackCat.say();
whiteDog = {name:"dog",food:"bone"};
blackCat.say.call(whiteDog);
bird = {food:"fly", name:"blue"};
blackCat.say.apply(bird);
3、常见问题
var obj = {
name: 'qiutc',
foo: function() {
console.log(this);
},
foo2: function() {
console.log(this);
setTimeout(this.foo, 1000);
}
}
obj.foo2();
现象:两次打印的this不一样
4、解决方案
可以这么这么解决:利用 闭包 的特性来处理
var obj = {
name: 'qiutc',
foo: function() {
console.log(this);
},
foo2: function() {
console.log(this);
var _this = this;
setTimeout(function() {
console.log(this); // Window
console.log(_this); // Object {name: "qiutc"}
}, 1000);
}
}
obj.foo2();
可以看到直接用 this 仍然是 Window;因为 foo2 中的 this 是指向 obj,我们可以先用一个变量 _this 来储存,然后在回调函数中使用 _this,就可以指向当前的这个对象了
第一次是 foo2 中直接打印 this,这里指向 obj 这个对象,我们毋庸置疑;
但是在 setTimeout 中执行的 this.foo ,却指向了全局对象,这里不是把它当作函数的方法使用吗?这一点经常让很多初学者疑惑;
其实,setTimeout 也只是一个函数而已,函数必然有可能需要参数,我们把 this.foo 当作一个参数传给 setTimeout 这个函数,就像它需要一个 fun 参数,在传入参数的时候,其实做了个这样的操作 fun = this.foo,看到没有,这里我们直接把 fun 指向 this.foo 的引用;执行的时候其实是执行了 fun() 所以已经和 obj 无关了,它是被当作普通函数直接调用的,因此 this 指向全局对象。
这个问题是很多异步回调函数中普遍会碰到的;
5、编码实战
var p = document.getElementsByTagName("p");
function cat(){}
cat.prototype={
name:"tom",
food:"fish",
say: function(){
console.log(this.name+" love "+this.food);
}};
var blackCat = new cat;
blackCat.say();
whiteDog = {name:"dog",food:"bone"};
blackCat.say.call(whiteDog);
bird = {food:"fly", name:"blue"};
blackCat.say.apply(bird);
function changeStyle(attr,value){
this.style[attr] = value;
}
var box = document.getElementsByTagName("p");
window.changeStyle.call(box[1],"borderTop","20px solid black");
6.扩展思考
问题:如何理解this?
当一个函数被调用时,拥有它的object会作为this传入。在全局下,就是window or global,其他时候就是相应的object。 也可以看到,call和apply就是利用这一点实现更改this 值的
分享
'use strict';
function foo() {
console.log(this);
}
setTimeout(foo, 1);
// window
现象:加了严格模式,foo 调用也没有指定 this,应该是出来undefined,但是这里仍然出现了全局对象
难道是严格模式失效了吗? 并不,即使在严格模式下,setTimeout 方法在调用传入函数的时候,如果这个函数没有指定了的 this,那么它会做一个隐式的操作—-自动地注入全局上下文,等同于调用 foo.apply(window) 而非 foo(); 当然,如果我们在传入函数的时候已经指定 this,那么就不会被注入全局对象,比如: setTimeout(foo.bind(obj), 1);;
7.参考文献
参考二: JavaScript 中的 this !
8、更多讨论
this含义为何如此丰富?
理解this的指向有何意义?
ppt地址:https://ptteng.github.io/PPT/PPT/js-02-js'this.html#/
评论