JavaScript中有许多令人困惑的地方,但是,因为这些东西让JavaScript更加强大。例如原型链,闭包等,其中包括this机制,处处坑。
This绑定规则
this机制有四种绑定的规则:默认绑定,隐式绑定 ,显式绑定 ,new绑定,分别对应函数四种调用方式:函数直接调用 , 对象方法调用,间接调用 ,构造函数调用。
**非严格模式下: **
this都会指向一个对象
默认绑定
全局环境,this指向window
console.log(this == window);//true
复制代码
独立调用的方法,this指向window
function fn (){
console.log(this==window);//true
}
复制代码
调用嵌套的函数,this指向window
function fn (){
function test(){
console.log(this == window);//true
}
test();
}
fn();
复制代码
以上是在非严格模式下情况。
在严格模式下,默认绑定有区别。非严格模式下this会绑定到上级作用域,而严格模式(use strict)时,不会绑定到window对象身上
function fn(){
'use strict';
console.log(this);//undefined
}
fn();
复制代码
隐式绑定
调用对象中的方法,该方法中this指向对象本身
let obj = {
count:1,
getCount(){
console.log(this);//obj
console.log(this.count);//1
}
}
obj.getCount();
复制代码
上述代码相当于
let obj = {
count:1,
getCount(){
console.log(obj);//obj
console.log(obj.count);//1
}
}
obj.getCount();
复制代码
显式绑定
通过call(),apply(),bind(),强制改变this指向
let count = 2
let obj = {
count:1,
getCount(){
console.log(this.count);//2
}
}
obj.getCount.call(this);
复制代码
let obj1 = {
a:'obj1’
},
obj2 = {
a:'obj2'
}
function fn(){
console.log(this.a);
}
fn.call(obj1);//obj1
fn.call(obj2);//obj2
复制代码
let obj = {
a:"obj"
}
let a = 'a'
function fn (param){
console.log(this.a);
console.log(param);
}
fn()//a
fn.call(obj,'call')//obj,call
fn.apply(obj,['apply'])// obj , ['apply']
let fnBind = fn.bind(obj);
fnBind('bind');//obj , 'bind'
复制代码
call(),apply(),bind()均可以改变this指向
call(),apply()与bind()的区别
fn.bind(obj)时,bind方法会返回一个已经绑定this的新函数。需要单独再次调用都会执行
let obj = {
name:'bind'
}
function fn (){
console.log(this.name);
}
let fn1 = fn.bind(obj);
fn1();//bind
复制代码
call(),apply()绑定this,并执行该方法
let obj = {
name:'obj',
getName(){
console.log(this.name);
}
}
let obj1 = {
name:'call'
}
let obj2 = {
name:'bind'
}
obj.getName.apply(obj2)//bind
obj.getName.call(obj1);//call
复制代码
apply()与call()的区别
两者在于传递的参数形式不同,apply()接收的参数为数组形式
new绑定
函数或者方法是使用new调用,它就当成构造函数调用。
function Fn (){
this.name = "fn";
}
let f = new Fn();
console.log(f);//{name: "fn"}
复制代码
一般使用构造函数不会使用return。new调用时,内部会创建一个this的对象将我们添加的属性挂到时this对象身上并返回。
如果在构造函数中return一个原始值,然后再进行new绑定,内部会忽略掉构造函数返回的原始值,自己创建一个对象并返回
function Fn(){
this.name = "fn";
return 1;
}
let f = new Fn();
console.log(f);//{name: "fn"}
复制代码
如果构造函数返回一个对象时,new绑定时内部不再自行创建,而是直接将对象返回即可
function Fn(){
this.name = "fn";
return {
name:'object',
age:20
}
}
let f = new Fn ();
console.log(f);//{name: "object", age: 20}
复制代码
This绑定丢失
别名丢失隐式绑定
var name = 'window';
let obj = {
name:'obj',
getName(){
return this.name;
}
}
let getName = obj.getName;
console.log(getName());//'window'
复制代码
回调丢失隐式绑定
const WITH_TIME = 1000;
let name = "window";
let obj = {
name:"obj",
getName(){
console.log(this.name);
}
}
setTimeout(obj.getName,WITH_TIME);//window
复制代码
This丢失修复
显式bind()绑定this
var name = 'window';
let obj = {
name:'obj',
getName(){
return this.name;
}
}
let getName = obj.getName.bind(obj);
console.log(getName());//'obj'
复制代码
es6剪头函数
const WITH_TIME = 1000;
let name = "window";
let obj = {
name:"obj",
getName(){
setTimeout(()=>{
console.log(this.name);//'obj'
},WITH_TIME);
}
}
obj.getName();
复制代码
This绑定优先级
显式绑定VS隐式绑定
function getName(){
console.log(this.name);
}
let obj1 = {
name:"javaScipt",
getName:getName
}
let obj2 = {
name:'Python',
getName:getName
}
obj1.getName();//'javaScipt'
obj2.getName();//'Python'
obj1.getName.call(obj2);//Python
obj2.getName.call(obj1);//javaScipt
复制代码
结论:显式绑定优先级大于隐式绑定
隐式绑定VSnew绑定
function getName(){
console.log(this.name);
}
let obj1 = {
name:"javaScipt",
getName:getName
}
let obj2 = {
name:'Python',
getName:getName
}
obj1.getName();//'javaScipt'
obj2.getName();//'Python'
let o1 = new obj1.getName();//undefined
let o2 = new obj2.getName();//undefined
复制代码
结论:new绑定优先级大小隐式绑定
显式绑定VSnew绑定
function getName(){
console.log(this.name);
}
let obj1 = {
name:"javaScipt",
getName:getName
}
let obj2 = {
name:'Python',
getName:getName
}
obj1.getName.call(obj2);//'Python'
obj2.getName.call(obj1);//'javaScitp'
let o1 = new obj1.getName.call(obj2);//obj1.getName.call is not a constructor
let o2 = new obj2.getName.call(obj1);//obj2.getName.call is not a constructor
复制代码
直接报错了,显式绑定与new绑定不能共用
bind()呢?
function getName(){
console.log(this.name);
}
let obj1 = {
name:"javaScipt",
getName:getName
}
let obj2 = {
name:'Python',
getName:getName
}
let f1 = obj1.getName.bind(obj2);
let f2 = obj2.getName.bind(obj1);
f1();//'Python'
f2();//'javaScitp'
let b1 =obj1.getName.bind(obj2);
let b2 = obj2.getName.bind(obj1);
let o1 = new b1();//undefined
let o2 = new b2();//undefined
复制代码
bind()会返回一个改变this指向的函数,然后new调用,this又改变了
结论: new绑定优先级大于显式绑定






















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)