this

一开始看到this这个单词..这个关键字的时候,我一直都把他当成英语里面的这个————即window或者调用这个的函数,后面问过一些学JAVA的人。也没怎么弄懂。今天特地翻了下资料。在此总结下。

到底啥是this

对于this变量最要的是能够理清this所引用的对象到底是哪一个,也许很多资料上都有自己的解释,但有些概念讲的偏繁杂。而我的理解是:首先分析this所在的函数是当做哪个对象的方法调用的,则该对象就是this所引用的对象总体原则就是:是谁调用的,this 就指向谁

this调用的一般几种情况

  • 全局调用
  • 作为对象的方法调用
  • 绑定事件调用

####当作为全局调用的情况
这么说吧 记住这一点全局变量都是window对象的属性这个时候this 一般指的就是window
比如这个例子

1
2
3
4
5
function arr (){
alert(this.name)
}
name="Z-one"
arr();

0_1462812500640_upload-5ebab0c0-77a2-452d-b89b-27a150ae59df
记住这一点全局变量都是window对象的属性一般单独调用的时候就是指向的全局window。


当作为对象的方法调用情况

还是来看这个例子

1
2
3
4
5
6
7
8
9
var x="Z-one";
var obj={};
obj.x="Acorn";
obj.y=function (){
alert(this.x)
}
var b=obj.y;
obj.y();
b();

0_1462813728591_upload-a055c8e0-6886-4a50-afa7-c21ebcabcea3
结果很明显了

  • 第一个obj,y() 是作为一个对象的方法调用的,这时候this 就自然而然的指向了这个对象.
  • 而第二个b()为什么会输出”Z-one”呢,因为这里var b=obj.y我的理解是相当于做了一个赋值,但是运行b() 的时候还是把b()当成一个单独调用的形式(全局变量的方式调用),就好比有100块放在银行里,我现在手里有个同样的100块,怎么说这100块也不可能是银行的啊。还是我的。

作为绑定事件调用的时候,

这个就更好理解了。

1
2
3
$("li").on("click",function(){
console.log(this.html());
})

这个时候this 就是指向的绑定事件的目标”li”

还有个比较特殊的一个setTimeout的时候

当被定时器调用的时候 情况又比较特殊。我们来看下面这个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
name="Z-one";
var obj={
name:"Acorn",
x:function(){
alert(this.name)
setTimeout(function(){
alert(this.name)
},1000)
}
}
var c=obj.x;
obj.x();
c();

0_1462815568904_upload-56e1bc67-ae44-412e-8707-4dc098d399d1
结果已经很明显了。

  • 第一个是属于当初一个对象的属性调用,this指向的是这个对象,this.name理所当然就是”Acorn”了,
  • 然后执行c()。这里是属于一个全局调用的情况。this指向window。
  • 然后就是两次定时器,这里记住一点。定时器也是指向的window.也就理所当然的是”Z-one”

在被作为对象的一个方法调用时候,在方法函数内部定义的函数(也就是函数中又存在一个函数)这时候this又有说不同

具体还是来看这个例子:

1
2
3
4
5
6
7
8
9
var obj={
x:function(){
function abc(){
alert(this.name)
}()
},
name:"Z-one"
}
var name ="xxx"

0_1462845801974_upload-fcacd4b8-49f2-4ba4-abfd-d22ebd1cde9f
当运行的时候. abc是这个自执行函数,这时候this 指向了全局.
现在就很明确了:

  • 当作为一个独立的函数调用(全局变量)的时候,根据是否是严格模式,this指向undefined或者window.
  • 当作为对象的方法调用时候,this 指向调用的对象
  • setTimeout这类的定时器,this 还是会指向window

如何改变this的指向呢?

还是上面那个例子,我如果想在函数内的二级函数内正常访问到我们想指的那个this 应该怎么办呢??
这里有两者方法

在一开始的时候,就是一级函数的时候,这时候this还是指向的我们想要的this。这时候我们就把这个this存起来

直接看代码

1
2
3
4
5
6
7
8
9
10
var obj={
x:function(){
var that=this;//这时候先把this存起来
(function abc(){
alert(that.name)
})()
},
name:"Z-one"
}
var name ="xxx"

0_1462846647791_upload-fdf4272c-26eb-42b7-acd5-71cf1ad4bb77
这像这样

利用call和apply 来改变this的指向,让其指向我们指向的执行上下文(通过改变this内部的指针)

1
2
3
4
5
6
7
8
9
function abc(){
console.log(this.name)
}
var obj={
name:"Z-one"
}
name="Acorn";
abc();
abc.call(obj)

0_1462848090358_upload-790d38fc-224a-45ee-a62d-e2bb7f9d794a
这样结果就很明显了。


call 和apply的区别

call 和apply的作用都是改变对象的执行上下文。简而言之就是改变对象的内部指针,即改变对象的this指向内容。
一般的调用是“对象调用函数”,但call aply 是“函数调用对象”
call 和apply的区别在于

  • call传入的是具体的值
  • apply传入的是一个数组

this的一些题目

下面代码输入什么

1
2
3
4
5
6
7
8
9
10
11
12
13
var john = { 
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi()




//输出 "jojn:hi!"
//这时候 调用方式是以一个对象的方法来调用,this指向的是这个对象

下面代码输出什么,为什么

1
2
3
4
5
6
7
8
9
10
func() 

function func() {
alert(this)
}


//这里 因为函数提升,func()是可以运行的
输出 window
这里 调用方式是作为独立的函数调用,this 指向window

下面代码输出什么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function fn0(){
function fn(){
console.log(this);
}
fn();
}

fn0();

//这里的调用方式属于 在一个函数内部调用了一个二级函数.这时候this 指向的是全局(非严格模式)或者undefeined(严格模式)


document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);

// 这里是作为绑定事件来调用.this 当然指的就是被绑定的元素.
第一个指向 document
第二个是 定时器比较特殊,指向的是全局window

下面代码输出什么

1
2
3
4
5
6
7
8
9
10
var john = { 
firstName: "John"
}

function func() {
alert( this.firstName )
}
func.call(john)
//输出 "john"
使用call改变了this的指向,让this指向了john这个函数.

下面代码输出什么

1
2
3
4
5
6
7
8
9
10
11
var john = { 
firstName: "John",
surname: "Smith"
}

function func(a, b) {
alert( this[a] + ' ' + this[b] )
}
func.call(john, 'firstName', 'surname')
//输出 'john Smith'
使用call改变了函数functhis的指向,另外传入的参数是firstNameSurname

下面代码有什么问题,如何修改?

1
2
3
4
5
6
7
8
9
10
11
12
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指什么
this.showMsg();
})
},

showMsg: function(){
console.log('饥人谷');
}
}

这里是当做一个绑定事件在调用,此时的this 指向的是$btn.
当点击$btn的时候,会在控制台输出这个$btn节点。并且会报错。显示showMsg()is not undefined
修改如下

1
2
3
4
5
6
7
8
9
10
11
12
13
var module= {
bind: function(){
that=this;//这里的this 还是指向的是这个对象。
$btn.on('click', function(){
console.log(this)
that.showMsg();
})
},

showMsg: function(){
console.log('饥人谷');
}
}

下面代码输出什么

1
2
3
4
5
6
7
8
9
10
11
obj = {
go: function() { alert(this) }
}

obj.go(); //此时是调用方式是,当一个对象的方法调用,this 指向是这个对象本身.输出 object Object

(obj.go)(); //这里还是当成一个对象的方法调用,只是是一个自执行函数? 输出object window

(a = obj.go)(); //这里相当于给a添加一个指针,指向obj.go 这个函数,然后自执行这个a 这个函数(a是全局变量),此时this 指向的是window.
(0 || obj.go)();//这里0一直是false,运算后会得到(obj.go)这么一个匿名函数,这个函数时存在于window层面,运行这个函数的时候,this指向的就是window
如果是(0 || obj.go()) 这时候 this 指向的就是obj