前端百题斩——js中的这些“this”指向都值得了解

开发 前端
this是javascript中的一个关键字,其使用方法类似于一个变量,是执行上下文中一个重要组成部分。其作用是可以在函数体内部获取当前的运行环境。

[[403989]]

14.1 简介

this是javascript中的一个关键字,其使用方法类似于一个变量,是执行上下文中一个重要组成部分。其作用是可以在函数体内部获取当前的运行环境。

14.2 指向

每个函数的this是在调用的时候基于函数的执行环境绑定的,this的指向完全取决于函数的调用位置。(下面均是在浏览器环境下进行测试的结果)

在全局环境下,this 始终指向全局对象(window), 无论是否严格模式;

  1. console.log(this); // window 

普通函数内部的this分两种情况,严格模式和非严格模式。

(1)非严格模式下,this 默认指向全局对象window

(2)严格模式下, this为undefined

  1. function fun() { 
  2.     console.log(this); // window 

对象内部方法的this指向调用这些方法的对象

(1)函数的定义位置不影响其this指向,this指向只和调用函数的对象有关;

(2)多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象, 而非window)。

  1. const obj = { 
  2.     a: 10, 
  3.     b: 20, 
  4.     addfunction () { 
  5.         return this.a + this.b; 
  6.     } 
  7. }; 
  8.  
  9. console.log(obj.add()); // 30 
  10. const add = obj.add
  11. console.log(add()); // NaN 

原型链中的方法的this仍然指向调用它的对象

  1. const obj = { 
  2.     a: 10, 
  3.     b: 20 
  4. }; 
  5.  
  6. const prototypeObj = { 
  7.     addfunction () { 
  8.         return this.a + this.b; 
  9.     } 
  10. }; 
  11.  
  12. Object.setPrototypeOf(obj, prototypeObj); 
  13.  
  14. console.log(obj.add()); // 30 

当函数通过Function对象的原型中继承的方法 call() 和 apply() 方法调用时, 其函数内部的this值可绑定到 call() & apply() 方法指定的第一个对象上, 如果第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它。(见后续代码)

通过bind方法绑定后, 函数将被永远绑定在其第一个参数对象上, 而无论其在什么情况下被调用。(见后续代码)

当函数被当做监听事件处理函数时, 其 this 指向触发该事件的元素(针对于addEventListener事件)

  1. <button id="testId">按钮</button> 
  2.  
  3. const btn = document.getElementById('testId'); 
  4. btn.addEventListener('click'function() { 
  5.  console.log(this); // <button id="testId">按钮</button> 
  6. }); 

内联事件中的this指向分两种情况:

(1)当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素

  1. <button onclick="console.log(this)">按钮</button> // 输出该DOM节点 

(2)当代码被包括在函数内部执行时,其this指向等同于 函数直接调用的情况,即在非严格模式指向全局对象window, 在严格模式指向undefined

  1. <button onclick="clickFun()">按钮</button> 
  2.  
  3. function clickFun() { 
  4.  console.log(this); // window 

对于延时函数内部的回调函数的this指向全局对象window(当然可以通过bind方法改变其内部函数的this指向)

  1. function Fun() { 
  2.     this.a = 10; 
  3.     this.method = function() { 
  4.         setTimeout(function() { 
  5.             console.log(this); // window 
  6.         }, 1000); 
  7.     } 
  8.  
  9. const fun = new Fun(); 
  10. fun.method(); 

由于箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值,所以 call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this 毫无影响。

  1. function Fun() { 
  2.     this.a = 10; 
  3.     this.method = function() { 
  4.         setTimeout(() => { 
  5.             console.log(this); // Fun {a: 10, method: ƒ} 
  6.         }, 1000); 
  7.     } 
  8.  
  9. const fun = new Fun(); 
  10. fun.method(); 

14.3 改变this指向

除了隐式绑定this的方式,还能够通过显示绑定的方式,通过call、apply、bind方式改变this指向,对于这三者的区别后续将有专门的百题斩去阐述,本节主要进行一波简单使用。

call()

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

  1. function method(val1, val2) { 
  2.     return this.a + this.b + val1 + val2; 
  3.  
  4. const obj = { 
  5.     a: 1, 
  6.     b: 2 
  7. }; 
  8.  
  9. console.log(method.call(obj, 3, 4)); // 10 

apply()

apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。

  1. function method(val1, val2) { 
  2.     return this.a + this.b + val1 + val2; 
  3.  
  4. const obj = { 
  5.     a: 1, 
  6.     b: 2 
  7. }; 
  8.  
  9. console.log(method.apply(obj, [3, 4])); // 10 

bind()

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

  1. function method(val1, val2) { 
  2.     return this.a + this.b + val1 + val2; 
  3.  
  4. const obj = { 
  5.     a: 1, 
  6.     b: 2 
  7. }; 
  8.  
  9. const bindMethod = method.bind(obj, 3, 4); 
  10. console.log(bindMethod); // [Function: bound method] 
  11. console.log(bindMethod()); // 10 

扩展

 

  • call() 和 apply()的区别是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组;
  • bind返回的是一个绑定函数,而call和apply返回的是运行结果;
  • 多次 bind() 是无效的,只会绑定到第一次调用的对象上;
  • call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this 毫无影响。

本文转载自微信公众号「执鸢者」,可以通过以下二维码关注。转载本文请联系执鸢者公众号。

 

责任编辑:武晓燕 来源: 执鸢者
相关推荐

2021-05-19 07:02:42

JS对象方法

2021-05-12 07:04:55

Js变量方式

2021-08-04 06:56:49

HTTP缓存前端

2021-07-14 07:00:53

浏览器技巧前端

2021-06-02 07:02:42

js作用域函数

2021-05-09 22:00:59

TypeofInstanceof运算符

2021-10-19 22:23:05

typeof方式Instanceof

2021-05-30 19:02:59

变量对象上下文

2021-06-09 07:01:30

前端CallApply

2021-11-19 09:01:09

防抖节流前端

2021-07-19 07:02:10

浏览器进程单进程浏览器

2021-07-26 05:01:55

浏览器渲染流程

2014-08-19 14:12:47

Windows

2021-10-18 09:01:01

前端赋值浅拷贝

2021-06-04 07:04:29

闭包JavaScript函数

2021-01-07 05:40:13

BLE模块Android

2021-06-11 06:54:34

原型构造函数

2021-07-05 07:02:33

前端跨域策略

2021-05-27 07:02:05

JavaScript代码设施

2018-10-09 14:34:58

开源KubernetesGit
点赞
收藏

51CTO技术栈公众号