This的四种绑定
this的绑定取决于它的调用位置,而不是取决于它的声明位置
function baz(){
//调用栈baz,当前调用位置全局
bar();
}
function bar(){
//调用栈baz->bar,调用位置baz
foo();
}
function foo(){
//调用栈baz->bar->foo,调用位置bar
}
baz();
this的默认绑定
首先是最常用的函数调用类型:独立函数调用。这条规则是无法应用其他规则时的默认规则。
function foo(){
console.log(this.a);
}
let a = 2;
foo();//2
foo()是直接使用不带任何修饰的函数引用进行调用,只能使用默认绑定。当中的this指向全局对象。但在严格模式下,则不能将全局对象用于默认绑定,this会绑定到undefined
this的隐式绑定
function foo(){
console.log(this.a);
}
let obj2 = {
a:42,
foo:foo
}
let obj1 = {
a:2,
obj2:obj2
}
let a=3;
obj1.obj2.foo();//42
无论foo无论是在obj中定义还是先定义在添加为应用,这个函数严格来说都不属于obj对象。然而在调用位置使用obj上下文来引用对象时,可以说函数被调用时obj包含对函数的引用。
当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。并且对象属性引用链只有最后一层调用位置起作用
隐式丢失
函数别名
let bar = obj2.foo; bar();//3
间接引用
let p = {a:4} obj2.foo();//42 (p.foo = obj2.foo)();//3返回值是目标函数引用调用位置是foo()引用默认绑定
回调函数
setTimeout(obj2.foo,1000);
参数传递的过程是一种隐式赋值
显式绑定
使用函数的call(...)、apply(...)来直接指定this的绑定对象。
function foo(){
console.log(this.a);
}
let obj = {
a:2
}
foo.call(obj);
使用bind解决隐式丢失(一些函数也有context选项确保指定的this)
function foo(something){
return this.a + something;
}
let obj = {
a:2
}
let a = 6;
let bar = foo.bind(obj);
let b = bar(3)//5
new绑定
js中的构造函数不属于某个类,也不会实例化一个类,它们只是被new操作符调用的普通函数
只用new调用函数会执行:
1. 构造一个全新的对象
2. 新对象会执行Prototype链接
3. 新对象会绑定到函数调用的this
4. 如果函数没有返回其他对象,new表达式中函数调用会自动返回这个新对象
function foo(a){
this.a = a;
}
let bar = new foo(2);
console.log(bar.a);//2
优先级:new绑定>显示绑定>隐式绑定>默认绑定
箭头函数
箭头函数不使用this的四种标准规则,而是根据外层作用域决定。箭头函数的绑定无法修改
function foo(){
return (a)=>{
//this继承自foo()
console.log(this.a)
}
}
let obj1 = {a:2}
let obj2 = {a:3}
let bar = foo.call(obj1)
bar.call(obj2)//2,不是3
function foo(){
setTimeout(()=>{
console.log(this.a);
},1000);
}
let obj = {a:2}
foo.call(obj);