【js】5种this绑定简析

this绑定/this指向

  1. 默认绑定 - window
  2. 隐式绑定 - context
  3. 显示绑定 - call、apply、bind
  4. new绑定 - 新对象
  5. 箭头函数绑定 - 上层作用域
1.默认绑定
function fn1() { let a = 1; let fn2 = function () { console.log(this); console.log(this.a); } fn2(); return fn2 } var a = 2; fn1() //window 2 fn1()() //window 2 window 2

无论函数在哪声明或调用,调用时函数前无对象,this最终都指向window
2.隐式绑定
function fn() { console.log(this.name); } let obj1 = { name: "boj1", fn } let obj2 = { name: "obj2", obj1 } obj2.obj1.fn() //obj1

【【js】5种this绑定简析】函数调用前有对象时,this就近指向上下文对象
若未寻找到属性返回 undefined,不会在obj2上找
隐式丢失
  1. 参数传递
  2. 变量赋值
参数传递
let name = "window" function fn() { console.log(this.name); } let obj1 = { name: "obj1", fn } let obj2 = { name: "obj2", obj1 } function func(param) { param() } func(obj2.obj1.fn) //window

fn作为参数在func中调用,this指向丢失,默认指向window
变量赋值
let name = "window" function fn() { console.log(this.name); } let obj1 = { name: "obj1", fn } let obj2 = { name: "obj2", obj1 } let func = obj2.obj1.fn func(); //window

将fn赋给func,func的调用this默认指向window
3.显示绑定
  1. bind
  2. call
  3. apply
bind
let name = "window" function fn() { console.log(this.name); } let obj1 = { name: "obj1", fn } let obj2 = { name: "obj2", obj1 } function func1(param) { param() } func1(obj1.fn.bind(obj2)) //obj2 let func2 = obj1.fn.bind(obj2) func2() //obj2

绑定:fn.bind(obj) 将fn绑定在obj上并返回一个函数,不管是参数传递还是变量赋值都 不会出现绑定丢失的情况
参数:bind第一个参数为绑定的对象,后面的可以追加参数作为函数的实参,传递一个 数组时不会自动解构
优先级:显示绑定>隐式绑定>默认绑定
硬绑定:绑定后不可使用bind、call、apply再 重新绑定
call
let name = "window" function fn() { let name = this.name return function fn1() { console.log(name, this.name); } } let obj1 = { name: "obj1", fn } let obj2 = { name: "obj2", obj1 } function func1(param) { param() } func1(obj1.fn.call(obj2)) //obj2 window let func2 = obj1.fn.call(obj2) func2() //obj2 window func2.call(obj1) //obj2 obj1

绑定:call绑定不同与bind的返回一个绑定的函数,而是 立即执行这个函数
参数:与bind相同,this指向第一个参数,后续参数作为实参,数组不自动解构
软绑定:本次调用时为绑定,下次执行还需要再次绑定
闭包:在绑定时只绑定最外层作用域,父函数返回的函数在调用时为 默认绑定,当对其绑定时,其this会被绑定,不影响外层作用域
apply
let arr = ["param1", "param2"] let name = "window" function fn(...arr) { console.log(this.name, arr[0], arr[1]); } let obj1 = { name: "obj1", fn } let obj2 = { name: "obj2", } obj1.fn.apply(obj2, arr)//obj2 param1 param2

绑定:apply与call相同,会 立即执行被绑定的函数,同样也是软绑定
参数:第一个参数也是绑定的对象,后面与call不同,apply传递的数组 会解构赋给函数的的形参
4.new绑定
function fn(name) { this.name = name } let obj = new fn("obj") console.log(obj.name); //obj console.log(new fn("new")); // {name:new}

用new去调用函数,会将该函数作为一个构造函数,把该函数的this指向一个新创建的对象,返回该对象
5.箭头函数 可以与call中的例子对比
let name = "window" function fn() { let name = this.name return () => { console.log(name, this.name); } } let obj1 = { name: "obj1", } let obj2 = { name: "obj2", } let func2 = fn.call(obj2) func2() // obj2 obj2 func2.call(obj1) // obj2 obj2 let func1 = fn.call(obj1) func1() //obj1 obj1

箭头函数没有自己的 this,它会使用上一层作用域的this
对箭头函数的绑定是没有效果的,修改指向需要修改上层作用域的this

    推荐阅读