this 到底指向谁:
谁调用它,this
就指向谁。
更确切的说法:this
的指向,是在调用函数时根据执行上下文所动态确定的。
- 在函数体中,简单调用该函数时(非显式/隐式绑定下),严格模式下
this
绑定到undefined
,否则绑定到全局对象window
/global
; - 一般构造函数
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 优先级相关
我们常常把通过 call
、apply
、bind
、new
对 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预设传参等(待完善)
参考资料:
侯策:前端开发核心知识进阶