this的行为解析

667 阅读2分钟

作者:小白君
转载请标明出处

1124676285_15615931321841n.jpeg

1. this的默认行为-默认绑定规则

独立函数调用时,应用默认绑定规则。可以看作无法应用其他规则时的默认规则

默认绑定规则,在非严格模式先指向window, 严格模式下指向undefined


function foo() {

    console.log(this.a)

}

// 这里不能用let或者const的原因是, var声明的变量会作为window的属性, let和const声明的变量并不会

var a = 2

foo() // 2

2. this的悄悄行为-隐式绑定

当函数调用时有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象上


function foo() {

    console.log(this.a)

}

let obj2 = {

    a: 42,

    foo: foo

}

let obj1 = {

    a: 2,

    obj2: obj2

}

// 对象属性引用链中只有上一层或者说最后一层在调用位置中起作用

obj1.obj2.foo() // 42

隐式丢失(对函数的引用调用, 传入回调函数时)


function foo() {

    console.log(this.a)

}

function doFoo(fn) {

    fn()

}

var obj = {

    a: 2,

    foo: foo

}

var a = 'oops, global'

doFoo(obj.foo) // oops, global

3. this的明面上的行为-显示绑定

通过call(..), apply(..), bind(..)this显示的绑定到摸个对象上


function foo() {

    console.log(this.a)

}

var obj = {

    a: 2

}

foo.call(obj) // 2

4. thisnew绑定行为

使用new调用函数时,会自动执行下面的操作

  1. 创建一个新的对象
  1. 这个新对象会被执行原型链连接
  1. 函数调用时的this绑定到这个对象上
  1. 如果函数没有返回其它对象,则自动返回这个对象

5. this绑定优先级

new绑定 > 显示绑定 > 隐式绑定 > 默认绑定

6. 箭头函数this绑定规则

在箭头函数内部, this绑定不是动态的, 而是词法的, 简言之箭头函数的this指向的是函数定义时的上下文对象,而不是调用时的上下文对象

箭头函数没有自己的arguments, 而是继承自父层

7. call, apply, bind实现

1. call实现


Function.prototype.callFn = function(context, ...args) {

    if (typeof this !== 'function') {

        throw new TypeError(this + ' is not a function')

    }

    if (typeof context === 'undefined' || context === null) {

        context = window

    }

    let fnSymbol = Symbol()

    context[fnSymbol] = this

    let result = context[fnSymbol](...args)

    delete context[fnSymbol]

    return result

}

2. apply实现


Function.prototype.applyFn = function(context, args) {

    if (typeof this !== 'function') {

        throw new TypeError(this + ' is not a function')

    }

    if (typeof context === 'undefined' || context === null) {

        context = window

    }

    let fnSymbol = Symbol()

    context[fnSymbol] = this

    let result = context[fnSymbol](...args)

    delete context[fnSymbol]

    return result

}

3. bind实现


Function.prototype.bindFn = function(context, ...thisArgs) {

    if (typeof this !== 'function') {

        throw new TypeError(this + ' is not a function')

    }

    if (typeof context === 'undefined' || context === null) {

        context = window

    }

    let self = this

    return function(...args) {

        return self.apply(context, args.concat(thisArgs))

    }

}

4. new 的实现


function newFn() {

    let newObj = {}

    Constructor = [].shift.call(arguments)

    newObj.__proto__ = Constructor.prototype

    const result = Constructor.apply(newObj, arguments)

    return typeof result === 'object' ? result : newObj

}