this
的情况一共分为5种
- 默认绑定:在严格模式下绑定是
undefined
,否则绑定到全局对象window
- 上下文调用,绑定到上下文对象(谁调用,
this
就是谁) - 由
call
/apply
/bind
调用,绑定到指定的对象 -
new
调用,绑定到new的对象 -
DOM
事件绑定,this就是绑定的哪个DOM
对象
本文不讨论严格模式
本文不讨论严格模式
本文不讨论严格模式
1.默认绑定
function foo(){
console.log(this.a);
}
var a = 2
foo() // 2
function foo(){
this.a = 3
console.log(this.a); //this->window this.a = window.a
}
foo() // 3
var a = 2
function foo(){
this.a = 4 //window.a = 4
var b = 5
console.log(this); //window
console.log(this.a); //4
console.log(this.b);//undefined
console.log(b); //5 这个就和作用域相关和this无关了
bar() //这里要注意的是虽然在foo里面调用了bar,但是bar前面没有点,所以bar的this仍是window,
//foo里面的var声明的变量b跟this一毛钱关系也没
}
foo()
function bar(){
console.log(this); //window
console.log(b) // Uncaught ReferenceError: b is not defined
//注意函数的作用域链是在声明的时候确定的
//这里是在全局声明的函数,所以找不到a这个变量从而产生了报错
}
2.上下文调用绑定
最基本的调用绑定
var a = 20
var obj = {
a:2,
foo:function(){
console.log(this.a);
}
}
console.log(obj.foo());
地址引用绑定
var a = 20
var obj = {
a:2,
foo:function(){
console.log(this.a);
}
}
obj.foo() //2
var bar = obj.foo
bar() //20
这里需要注意的是bar = obj.foo实际上是bar引用的foo的堆内存地址。
bar()前面没有点,那么他的this就是window,所以这里打印出来的是20而不是2
var a = 20
function foo(){
var a = 4
return {
a:100,
bar:function(){
console.log(this.a);
console.log(a);
}
}
}
var zpt = foo()
var ngx = zpt.bar
zpt.bar() //100 4
ngx() //20 4
---------------------------
这里呢zpt等于foo函数执行返回的对象,那么
zpt = {
a:100,
bar:function(){
console.log(this.a);
console.log(a);
}
zpt.bat() 看到bar前面有点,那么this就是zpt
所以第一个a是100 第二个a是foo作用域中的a,那么就是4
对于ngx = zpt.bar ngx是引用的bar函数的声明地址
ngx()的时候前面没有点 那么他的this就是winodw
那么第一个打印的就是window的a,也就是20,第二个a是bar声明的时候进行作用域查找,在foo作用域找到了,那么第二个a仍然是4
一定要区分this和作用域的区别
作用域在声明的时候确定
this在执行的时候确定
3.new绑定
谁new了他,那么this就是谁,这个没啥好讲的
name = 100
function Person (name) {
this.name = 1
}
Person.prototype.talk = function () {
console.log(this.name)
}
var bar = new Person()
bar.talk() // 1
4.call/bind/apply绑定
var a = 20
var obj = {
a:2,
foo:function(){
console.log(this.a);
setTimeout(function(){
console.log(this.a);
},1000)
}
}
obj.foo() // 2 20
为什么foo的第二个a是20呢
是因为settimeout里面的匿名函数是在1秒后执行的,
但是执行这个函数的时候,前面没有点啊!!!那么他的this就是window了
如果我们在后面bind(this)
var a = 20
var obj = {
a:2,
foo:function(){
console.log(this.a);
setTimeout(function(){
console.log(this.a);
}.bind(this),1000)
}
}
obj.foo() // 2 2
那么就是正常的了
除开DOM绑定,所有的回调函数执行的时候,只要前面没有点,他们的this永远是window
var data1 = "def";
function func2(callBack) {
callBack()
}
vice = {
"data1" : "abc"
};
vice.trans = function () {
alert(this.data1);
};
vice.func1 = function (callBack) {
func2(callBack);
};
vice.func1(vice.trans); //def this变成了window
你把vice.trans实际上就是函数声明时候的堆内存地址
callBack()执行的时候前面没有点,那么不好意思,this就是window
5.DOM绑定
DOM的事件绑定有3种情况
- 直接在直接在html标签中绑定
this
永远是window
<button id="btn" type="button" onclick="showThis()">点击</button>
function showThis(){
console.log(this);
}
可以看到this指向的是window
<button id="btn" type="button" onclick="showThis(this)">点击</button>
function showThis(ctx){
console.log(this);
console.log(ctx);
}
如果想要这个DOM上的this,那么我们需要把this作为参数传进去
- js绑定(对象形式)
var btn = document.getElementById("btn")
btn.onclick=function(){
console.log(this);
}
onclick
- js绑定(监听形式)
document.getElementById("btn").addEventListener("click", function(){
console.log(this);
});
addEventListener
比如改变类的this
function Person () {
this.name = '张三'
}
Person.prototype.talk = function () {
console.log(this);
}
var Grey = new Person()
var btn = document.getElementById("btn")
btn.onclick=Grey.talk // <button id="btn" type="button" >点击</button>
网友评论