this
this是 JavaScript 语言的一个关键字。
它是函数运行时,在函数体内部自动生成的一个对象。
this总是指向调用它的对象
三个简单的应用场景
this一般用在函数,这里我根据函数的三个场景,通俗的分析下this的问题。
先不说this问题,我们先说说全局对象window。
你通过var定义的参数以及函数,实际上是全局对象window的一个属性。怎么说呢,看下下面的代码。
var x = 1;
function test() {
console.log('I am function');
}
console.log(x); //1
console.log(window.x); //1
test(); //I am function
window.test(); //I am function
通过上面的代码。就可以粗略理解成JavaScript中函数和var定义的参数实际是window的一个属性*。
(在这篇博客中,指javascript的普通环境,不涉及node.js的环境,因为node的全局对象不是window,而是Global)
在普通函数中调用
var x = 1;
function test(){
console.log(this.x);
}
test(); //1
此时test,实际是通过window调用的,所以这里this指向window。
作为对象方法的调用
test = function () {
console.log(this.x);
};
var obj = {
x:2,
test:test
};
obj.test(); //2
此时test,通过obj调用,所以这里this指向obj,obj中x为2,所以打印2。
构造函数中调用
function test() {
this.x = 1;
}
var obj = new test();
console.log(obj.x); //1
在构造函数中,this指向new出来的这个新对象。obj是test构建出来的,此时this指向obj。
稍微复杂点
var x = 1;
function test() {
this.x = 2;
}
var obj = new test();
alert("obj.x: " + obj.x); //2
obj.x = 3;
test();
x *= 10;
alert("ojb.x: " + obj.x); //3
alert("x: " + x); //20
如果你能看懂上面的运行结果,那说明你this已经入门了。如果看不懂,那看看下面的代码。
var x = 1;
function test() {
this.x = 2;
}
var obj = new test();
alert("obj.x: " + obj.x); //2
obj.x = 3;
window.test();
window.x *= 10;
alert("ojb.x: " + obj.x); //3
alert("x: " + window.x); //20
对比下,其实就是就是test和x在没被谁调用时,通过window调用他们,结果却是一样的,这就是平常容易出错的点。下面我详细说明下这段代码的过程。
1、var x 创建了一个全局的x,这个x算是window的一个属性。
2、test是一个函数(可以是普通函数,也可以是构造函数)。
3、通过test构造obj对象。
4、obj.x就是obj的属性x。
5、 obj.x = 3,修改了obj里面的x。
6、test(),在没用通过new的情况下,这里的test不是构造函数,而是window属性中的一个普通函数,实际通过window调用,此时this指向window,所以x是window的x。
7、x *= 10,这里的x就很明显是window的x了。
8、最终obj.x=3
9、最终window.x = 20
通过call,apply,bind改变this指向
这三都是用来改变this指向的,第一个参数是this指向的新对象,区别于第二个参数,以及返回值。
话不多说,直接代码解释
var name = 'lin';
var xw = {
name : "小王",
gender : "男",
age : 20,
bb:function(){
console.log(this.name)
},
say : function(school,grade) {
console.log(this.name + " , " + this.gender + " ,今年" + this.age + " ,在" + school + "上" + grade);
}
};
var xh = {
name : "小红",
gender : "女",
age : 21
};
xw.say('清华','大学'); //小王 , 男 ,今年20 ,在清华上大学
xw.say.call(xh,'北大','大学'); //小红 , 女 ,今年21 ,在北大上大学
xw.say.apply(xh,['北大','大学']); //小红 , 女 ,今年21 ,在北大上大学
xw.say.bind(xh,'北大','大学')(); //小红 , 女 ,今年21 ,在北大上大学
xw.bb.call(); //lin
xw.bb.call(undefined); //lin
xw.bb.call(null); //lin
首先,有xw(小王)和xh(小红)两个对象。小红没有say这个方法。
xw自然可以调用自己的say方法,say方法中的this指向调用它的xw。
然后,我们可以利用call,apply,bind来改变say这个方法的this,让小红也能调用这个方法。
三个方法第一个参数都是xh,改变this指向,让this指向xh。
第二个参数,call和bind都是say方法中需要的参数,而apply是say方法中需要的参数组成的数组。
bind会返回改变this指向后的say方法,我们需要调用这个方法,不然没什么效果,所以得加()调用。
最后三行代码,当你不给这三个函数传参或者传了一个null或者undefined时,默认调用全局对象,将window传给这三函数,所以才会打印全局的name。