一、this指向的四种规则
1.默认绑定规则
对象指向,比较的是引用地址。
console.log(this === window); //true
console.log({} === {}); //false
//函数的独立调用
function test(){console.log(this === window); //true
}
test();
2.隐式绑定规则
谁调用就指向谁。
let a = 0;
let obj = {a:2,foo:function(){console.log(this) //obj}}
obj.foo();
这里foo.function是obj对象里面的foo属性,是一个函数。当我们用对象的属性的方式调用这个方法的时候,那么this指向obj。
但如果foo写的是箭头函数,this就指向window了。
let a = 0;
let obj = {a:2,foo:() => {console.log(this) //window or global object}}
obj.foo();
那么下面两个this是否相同呢?
这两个this自然不是同一个this,因为不同函数执行产生不同的AO,所以每个函数有自己的this指向,但指向有可能相同(由当前执行方式决定)。
这里的相同说的是指向对象是同一个,但是他们的函数内部是不相等的,地址不同。
let a = 0;
let obj = {a:2,foo:function(){console.log(this) //objfunction test(){console.log(this); //window}test(); //独立调用就指向window}}
obj.foo(); //这里是obj调用
下面这里立即执行我们要看执行环境,指向相应的全局对象。
这里立即执行函数全都指向window,因为这里是浏览器环境。
let a = 0;
let obj = {a:2,foo:function(){console.log(this) //obj//立即执行函数全都指向window(function(){ console.log(this); //window})()}}
obj.foo();
闭包:闭包就是内层函数引用外层函数的变量。当函数调用的时候,导致内部新函数被定义,并抛出内部被定义的新函数。
作用:延长变量的声明周期。
let a = 0;
let obj = {a:2,foo:function(){console.log(this) //objfunction test(){console.log(this); //window}return test;}}
obj.foo()(); //调用的时候依旧是独立调用相当于test()
隐式丢失
变量赋值
当方法被赋值的时候存在一种例外的现象,它调用了却没有指向它,管这种现象叫隐式丢失。其实本质还是看函数怎么执行的就可以了。也可以去看一下=赋值的原理。
我们知道this指向是在函数执行时产生的。而下面这段代码中是先将obj对象的属性赋值给b,然后再执行的。所以这里foo只是把只想空间的地址赋给b了,但是空间里的this指向没有任何改变。
let a = 0;
function foo(){console.log(this)
}
let obj = {a:2,foo:foo
}
obj.foo(); //obj 对象调用
let b = obj.foo;
b(); //window 独立调用
let c = foo;
c(); //window 独立调用
foo(); //window 独立调用
参数赋值
函数传参过程就是变量赋值,应为js只有按值传递,那么这就也会考虑到隐式丢失的问题。
let a = 0;
function foo(){console.log(this);
}
function b(x){x(); //window
}
let obj={a:2,foo:foo
}
//预编译的过程中,实参被赋值为形参。(值的拷贝的过程,浅拷贝)
b(obj.foo);
父函数有能力决定子函数的this指向。
new 把函数当做构造函数执行,this指向实例。
let a = 0;
function foo(){console.log(this);
}
function b(x){x(obj); //windownew x(); //强行指向实例之后的对象foox.bind(obj)(); //强行指向obj
}//api 接口中指明的//回调函数:父函数,子函数
var arr = [1,2,3];
arr.forEach(function(item, idx, arr){console.log(this); //window
},this)
arr.sort(function(a, b){console.log(this); //windowreturn a-b;
})
setInterval(function(){console.log(this); //window
})let obj={a:2,foo:foo
}
//预编译的过程中,实参被赋值为形参。(值的拷贝的过程,浅拷贝)
b(obj.foo);