💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、豆包、星火、月之暗面及文生图、文生视频 广告
[TOC] # this ## this 是什么 this 是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。 <br> 当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this 就是记录的其中一个属性,会在函数执行的过程中用到。 > 需要明确的是,this 在任何情况下都不指向函数的词法作用域。在JavaScript 内部,作用域确实和对象类似,可见的标识符都是它的属性。但是作用域“对象”无法通过JavaScript代码访问,它存在于JavaScript 引擎内部。 ## 优先级 现在我们可以根据优先级来判断函数在某个调用位置应用的是哪条规则。可以按照下面的顺序来进行判断: 1. 函数是否在new 中调用(new 绑定)?如果是的话this 绑定的是新创建的对象。 ~~~ var bar = new foo() ~~~ 2. 函数是否通过call、apply(显式绑定)或者bind?如果是的话,this 绑定的是 指定的对象。 ~~~ var bar = foo.call(obj2) ~~~ ~~~ // 不管我们给函数`bind`几次,`fn`中的`this`永远由第一次`bind`决定 let a = {} let fn = function () { console.log(this) } fn.bind().bind(a)() // => window ~~~ 3. 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上 下文对象。 ~~~ var bar = obj1.foo() ~~~ 4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局对象。 ~~~ var bar = foo() ~~~ ## 例外 ### 被忽略的this 如果你把null 或者undefined 作为this 的绑定对象传入call、apply 或者bind,这些值 在调用时会被忽略,实际应用的是默认绑定规则: ~~~ function foo() { console.log( this.a ); } var a = 2; foo.call( null ); // 2 ~~~ 然而,总是使用null 来忽略this 绑定可能产生一些副作用。如果某个函数确实使用了 this(比如第三方库中的一个函数),那默认绑定规则会把this 绑定到全局对象(在浏览 器中这个对象是window),这将导致不可预计的后果(比如修改全局对象)。 ### 间接引用 ~~~ function foo() { console.log( this.a ); } var a = 2; var o = { a: 3, foo: foo }; var p = { a: 4 }; o.foo(); // 3 (p.foo = o.foo)(); // 2 ~~~ 赋值表达式 `p.foo = o.foo` 的返回值是目标函数的引用,因此调用位置是 `foo()` 而不是`p.foo()` 或者 `o.foo()`。根据我们之前说过的,这里会应用默认绑定。 > 注意:对于默认绑定来说,决定this 绑定对象的并不是调用位置是否处于严格模式,而是函数体是否处于严格模式。如果函数体处于严格模式,this 会被绑定到undefined,否则this 会被绑定到全局对象。 ### 箭头函数 箭头函数其实是没有`this`的,箭头函数中的`this`只取决包裹箭头函数的第一个普通函数的`this`。 ~~~ function a() { return () => { return () => { console.log(this) } } } console.log(a()()()) ~~~ 在这个例子中,因为包裹箭头函数的第一个普通函数是`a`,所以此时的`this`是`window`。另外对箭头函数使用`bind`这类函数是无效的。 ![](https://box.kancloud.cn/7f034f6e1a8b4a137b8b1a1cba320869_744x531.png) # 参考资料 * 前端面试之道 - 掘金小册 * 你不知道的JavaScript(上册)