侯策《前端开发核心知识进阶》读书笔记——Javascript中的this

this 到底指向谁:

谁调用它,this 就指向谁。

更确切的说法:this 的指向,是在调用函数时根据执行上下文所动态确定的。

  • 在函数体中,简单调用该函数时(非显式/隐式绑定下),严格模式下 this 绑定到 undefined,否则绑定到全局对象 windowglobal
  • 一般构造函数 new 调用,绑定到新创建的对象上;
  • 一般由 call/apply/bind 方法显式调用,绑定到指定参数的对象上;
  • 一般由上下文对象调用,绑定在该对象上;
  • 箭头函数中,根据外层上下文绑定的 this 决定 this 指向。

全局环境下的this

function f1 () {
    console.log(this)
}
function f2 () {
    'use strict'
    console.log(this)
}
f1() // window
f2() // undefined

上下文对象调用中的 this

const person = {
    name: 'Lucas',
    brother: {
        name: 'Mike',
        fn: function() {
            return this.name
        }
    }
}
console.log(person.brother.fn())
//Mike

this 指向最后调用它的对象,因此输出将会是:Mike

bind/call/apply 改变 this 指向

const target = {}
fn.call(target, 'arg1', 'arg2')
const target = {}
fn.apply(target, ['arg1', 'arg2'])
const target = {}
fn.bind(target, 'arg1', 'arg2')()

构造函数和 this

new 操作符调用构造函数,具体做了什么?

  • 创建一个新的对象;
  • 将构造函数的 this 指向这个新对象;
  • 为这个对象添加属性、方法等;
  • 最终返回新对象。
var obj  = {}
obj.__proto__ = Foo.prototype
Foo.call(obj)

如果构造函数中显式返回一个值,且返回的是一个对象,那么 this 就指向这个返回的对象;如果返回的不是一个对象,那么 this 仍然指向实例。

function Foo(){
    this.user = "Lucas"
    const o = {}
    return o
}
const instance = new Foo()
console.log(instance.user)
//undefined

function Foo(){
    this.user = "Lucas"
    return 1
}
const instance = new Foo()
console.log(instance.user)
//Lucas

箭头函数中的 this 指向

箭头函数使用 this 不适用以上标准规则,而是根据外层(函数或者全局)上下文来决定。

const foo = {  
    fn: function () {  
        setTimeout(function() {  
            console.log(this)
        })
    }  
}  
console.log(foo.fn())
//windows

const foo = {  
    fn: function () {  
        setTimeout(() => {  
            console.log(this)
        })
    }  
} 
console.log(foo.fn())

// {fn: ƒ}

this 优先级相关

我们常常把通过 callapplybindnew 对 this 绑定的情况称为显式绑定;根据调用关系确定的 this 指向称为隐式绑定。

显示绑定优先级>隐示绑定优先级

new 的优先级 > bind的优先级

实现一个 bind 函数

Function.prototype.bind = Function.prototype.bind || function (context) {
    var me = this;
    var args = Array.prototype.slice.call(arguments, 1);
    return function bound () {
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);
        return me.apply(context, finalArgs);
    }
}

考虑bind预设传参等(待完善)

参考资料:

侯策:前端开发核心知识进阶

原文地址:https://www.cnblogs.com/fmyao/p/12787426.html