javascript基础系列之what's this?(含bind,apply,call,new的实现,箭头函数)

106 阅读3分钟

在javascript中this出现的频率很高,我们总是能看见var serlf = this 或者 var _this = this之类的操作。那么到底this是什么? 先抛个答案:函数的上下文context,this完全取决于函数的调用位置。 常见的错误看法有1)this指向函数本身;2)this指向函数的词法作用域

为何要用this

this可以用来隐式传参

function identify(){
    return this.name.toUpperCase()
}
function speak(){
    var greeting = "Hello, I'm " + identify.call(this)
    console.log(greeting)
}
var me ={
    name:"Kyle"
}
var you ={
    name:"Reader"
}
identify.call(me)//KYLE
speak.call(you)//Hello, 我是KYLE

//如果不用this
function identify(context){
    return context.name.toUpperCase()
}
function speak(context){
    var greeting = "Hello, I'm " + identify.call(context)
    console.log(greeting)
}
identify(you)//READER
speak(me)//Hello, I'm KYLE

this的规则

  1. 对于直接调用不带任何修饰的函数进行调用,那么其this指向全局对象,在浏览器中为window,Nodejs中为global(PS:1)其实也相当于window.fn();2)在一个函数内部直接调用另一个函数,那么另一个函数的this也是指向全局)
  2. 隐式绑定:在对象内部使用函数,那么函数的this指向这个对象,此时,函数也被成为方法;值得注意的是当函数作为回调函数传入的时候this会丢失,导致函数产生错误,因为才有了开头var that = this这种写法
//隐式丢失
function foo(){
    console.log(this.a)
}
var obj ={
    a:2,
    foo
}
var bar = obj.foo
bar()//报错 找不到a
  1. 硬绑定:1)bind,apply,call方法;2)某些函数如forEach()可以传入obj作为参数来实现硬绑定
  2. new绑定
function new(constructor){
    //1.创建一个新对象
    const obj ={}
    //2.将新对象的原型与构造函数的原型链接
    obj.prototype = constructor.prototype
    //3.构造函数在新对象内部运行
    const res = constructor.apply(obj,arguments)
    //4.如果构造函数的运行结果是对象就返回该对象,否则返回obj
    return (res instanceof Object) ? res : obj
}

绑定级别

new > bind/apply/call > 隐式 > 直接调用

//bind实现
Function.prototype.myBind(){
    const that = this
    const obj = arguments[0]
    const args = [].slice.call(arguments).slice(1)
    return function Fn(){
        //判定是否执行了new操作
        //在执行new操作的时候,Fn运行在对象的内部,this就为新对象,
        //如果new成功了,那么新对象就是返回的Fn函数的实例
        if(this instanceof Fn){
            return new that(...args, ...arguments)
        }else{
            return that.apply(obj, args.concat([].slice.call(arguments))
        }
    }
}

//apply实现
Function.prototype.myApply(){
    const obj = arguments[0]
    const args = arguments[1]
    obj.fn = this
    let result
    if(args.length>0){
        result = obj.fn(...args)
    }else{
        result = obj.fn()
    }
    delete obj.fn
    return result
}

//call实现
Function.prototype.myCall(){
    const obj = arguments[0]
    const args = Array.from(arguments).slice(1)
    obj.fn = this
    const result = obj.fn(...args)
    delete obj.fn
    return result
}

箭头函数

  1. this完全指向词法作用域,因此经常将箭头函数作为回调函数传入,防止this丢失;另外在原型脸上定义函数的时候不要使用箭头函数,否则会丢失对象;bind,call,apply不能改变其作用域
  2. 不可以用作构造函数
  3. 不可以使用arguments对象,但是可以用rest参数
cosnt fun = (...args) =>{
    console.log(args)
}
fn(1,2,3) //[1,2,3]
  1. 不可以使用yiled命令,因此不能作为生成器函数