重学JavaScript高级(一):this指向问题

91 阅读4分钟

image.png

this的绑定

this的指向是什么东西

  • 函数在调用时候,js会默认给this绑定一个值
  • this的绑定和定义位置(编写位置)没有关系
  • this的绑定和调用方式以及调用位置有关系
  • this是在运行的时候被绑定的

绑定规则

  • 默认绑定:在严格模式下,this指向就是undefined

    //独立调用
    function foo(){
        console.log(this)
    }
    foo()//this指向window
    
    
    let obj = {
        bar:function foo(){
            console.log(this)
        }
    }
    obj.bar()//这样调用不属于独立调用,this指向obj
    let foo = obj.bar
    foo()//这样就属于独立调用,this指向的是window
    
  • 隐式绑定:通过某个对象进行调用

    let obj = {
        bar:function foo(){
            console.log(this)
        }
    }
    obj.bar()//这样调用不属于独立调用,this指向obj
    
  • 显示绑定

    • apply、call通过很明显的方式指定this的指向
    let obj = {
        name:"obj"
    }
    function foo(){
        console.log(this)
    }
    //这样this的指向就指向了固定的内容
    foo.call(obj)
    foo.call("123")
    
    foo.apply(obj)
    foo.apply("123")
    
    //call和apply最大的区别就是,传参的问题
    //call第一个参数是明确this的指向,后面的都是参数
    foo.call(obj,name,18)
    //apply第一个参数是明确this的指向,传参的时候要传递一个数组
    foo.apply(obj,[name,18])
    
    • bind显示绑定,会重新创建一个新的绑定函数
    let obj = {
        name:"obj"
    }
    function foo(){
        console.log(this)
    }
    
    let bar = foo.bind(obj,'zhangchang',18)//传参方式与call一致
    bar()//表面上是独立调用,但是通过bind后,bind的绑定优先级比默认绑定的优先级要高,所有this指向的就是obj
    
  • new绑定

    • js中的函数可以当作一个类的构造函数来使用,也就是new关键字
    • 当用new关键字调用函数后
      • 创建一个全新的对象
      • 这个新对象会被执行prototype链接
      • 这个新对象会被绑定到this指向上
      • 如果函数没有返回其他对象,表达式会返回这个新的对象
    function foo(){
        console.log(this)
    }
    new foo()//指向的就是foo对象
    

内置函数的绑定思考

  • 根据经验进行判断
//这种浏览器内置的函数,我们不能确定是怎么进行调用
setTimeout(function(){
    //指向window
    //内部显示的指向window
    console.log(this)
})

this绑定的优先级比较

new>bind>apply/call>隐式>默认

  • 默认绑定的优先级最低
  • 显示绑定高于隐式绑定
  • new绑定高于隐式的
  • new和apply与call使用,但是可以和bind使用
  • new优先级高于bind
function foo(){
    console.log(this)
}
let obj = {foo:foo}

//this指向肯定是foo
obj.foo()

//这里既有隐式绑定也有显示绑定,显示绑定的优先级会更高
obj.foo.apply("123")

this规则之外

  • 总有一些语法,会超出规则之外
  • 在显示绑定中,出现了null和undefined
//在非严格模式下指向window
//在严格模式下指向的就是null和undefined
fn.apply(null)
fn.apply(undefined)
  • 创建一个函数的间接引用,使用的是默认绑定规则

    function foo(){
        console.log(this)
    }
    
    let obj1 = {
        name:"obj1",
        foo:foo
    }
    
    let obj2 = {
        name:"obj2"
    }
    
    obj1.foo()//指向obj1
    (obj2.foo = obj1.foo)()//指向window,我认为可以当作独立调用
    

箭头函数 arrow function

function foo(){
    
}
let foo2 = function(){
    
}

let foo3 = (name,age)=>{}
  • 箭头函数不会绑定this,arguments
  • 箭头函数不能作为构造函数来使用(不能和new一起使用,会抛出错误)
//参数只有一个参数,括号可以省略
arr.forEach(item=>{console.log(item)})

//如果函数体中只有一行代码,大括号可以省略
arr.forEach(item=>console.log(item))

//如果只有一行代码,这行代码的结果会作为函数的返回值返回
arr.filter(item => item % 2 ==0)//返回偶数

//如果默认返回值是一个对象,这个对象必须加()
let arrFn = () =>123
console.log(arrFn())//返回123

let arrFn = () =>({name:"zhangcheng "})
console.log(arrFn())//返回{name:"zhangcheng "}

  • 箭头函数中的this使用
//箭头函数中没有this,会在自己身上找this,之后会向上查找this
//可以将箭头函数中的this,设想成为自由变量,不看函数被谁调用的,而是看声明的地方向上查找
let bar = ()=>{
    console.log(this)
}
bar.apply(123)//指向的依旧是this


//具体使用
//这是工具函数
function request(url,callback){
    let res = [1,2,3]
    callback(res)
}