转载于https://www.cnblogs.com/echolun/p/11962610.html
this绑定的5种场景(默认绑定、隐式绑定、显式绑定、new绑定、箭头函数绑定)
1.this默认绑定
默认绑定我们可以理解为函数调用时无任何调用前缀的场景,这里的this指向全局对象(非严格模式)
function fn1(){
let fn2=function(){
console.log(this);//window
fn3();
};
console.log(this);//window
fn2();
};
function fn3(){
console.log(this);//window
};
fn1();
//在严格模式环境中,默认绑定的this指向undefined
function fn4(){
console.log(this);//window
console.log(this.name);//听风就是雨
};
function fn5(){
"use strict";
console.log(this);//undefined
console.log(this.name);
};
var name="听风就是雨";
fn4();
fn5();// Cannot read property 'name' of undefined
//函数以及调用都暴露在严格环境下
"use strict";
var name="听风就是雨";
function fn6(){
console.log(this);//undefined
console.log(this.name);//报错
}
fn6();
// 在严格模式下调用不在严格模式中的函数,并不会影响函数执行指向
var name="听风就是雨";
function fn(){
console.log(this);//window
console.log(this.name);//听风就是雨
}
(function(){
"use strict";
fn();
}());
2.this的隐式绑定
function fn(){
console.log(this.name);//听风是风
};
let obj={
name:'听风是风',
func:fn
};
obj.func();
// 如果函数调用前存在多个对象,this指向距离调用自己最近的对象
function fn1(){
console.log(this.name);//wendy
}
let obj1={
// 如果把name:wendy注释掉,将输出undefined;
// name:"wendy",
fun1:fn1,
};
let obj2={
name:"听风吧",
fun2:obj1,
};
obj2.fun2.fun1();
</script>
番外---------作用域链和原生链的区别:
1.当访问一个变量时,解释器会先在当前作用域查找标识符,如果没有找到就去父作用域找,作用域链顶端就是全局作用域window,如果window都没有这个变量就会报错。
2.当在对象上访问某属性时,首先i会查找当前对象,如果没有就顺着原生链往上找,原生链顶端是null,如果全程都没有找到则返回一个undefined,而不会报错。
3.显式绑定
显式绑定是指我们通过call、apply、bind方法改变this的行为,我们能清楚的感知this指向变化过程。
注意:如果在使用call之类的方法改变this指向时,指向参数的是null和undefined时,this指向全局对象。
call和apply在改变this指向的同时会指向函数,而bind在改变this后是返回一个全新的boundFunction绑定函数。
<script type="text/javascript">
let obj1={
name:'wendy'
};
let obj2={
name:'sally',
};
let obj3={
name:'tom',
};
var name="听风就是风";
function fn(){
console.log(this.name);
};
fn();//听风就是风
fn.call(obj1);//wendy
fn.apply(obj2);//sally
fn.bind(obj3)();//tom
fn.call(null);//听风就是风
fn.apply(undefined);//听风就是风
let boundFn=fn.bind(obj1);
boundFn.call(obj2);//wendy
boundFn.apply(obj3);//wendy
boundFn.bind(obj2)();//wendy
</script>
4.new绑定以及this绑定的优先级
new一个函数发生以下3步:
1.以构造器的prototype属性为原型,创建新对象
2.将this和调用参数传给构造器,执行;
3.如果构造器没有手动返回现象,则返回第一步创建对象
this绑定的优先级
显式绑定 > 隐式绑定 > 默认绑定
new绑定 > 隐式绑定 > 默认绑定
<script type="text/javascript">
function Fn(){
this.name='听风就是风';
};
let echo=new Fn();
console.log(echo.name);//听风就是风
</script>
5.箭头函数的this
箭头函数中没有this,箭头函数的this指向取决于外层作用域中的this,外层作用域或函数的this指向谁,箭头函数中的this就指向谁。一旦箭头函数的this绑定成功,也就无法改变。
箭头函数的this也不是真的无法修改,我们看可以修改外层函数this指向达到间接修改箭头函数this的目的
<script type="text/javascript">
function fn(){
return()=>{
console.log(this.name) ;
}
}
let obj={
name:'wendy'
};
let obj1={
name:'sally'
};
let bar=fn.call(obj);//箭头指向obj
bar.call(obj1);//输出的是wendy
</script>