专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

入门JavaScript中的this指向(ES6)

1、引言

想要理解this,你可以先记住以下两点:

  • this永远指向一个对象;
  • this的指向完全取决于函数调用的位置

在JavaScript语言之中,一切皆对象,运行环境也是对象,所以函数都是在某个对象下运行,而this就是函数运行时所在的执行上下文(对象),所以this的指向是动态的。JS 中函数调用主要有以下几种模式:

75_1.png不同的函数调用方式会有不同的上下文,理解this的关键就是:对应的是 哪一种函数调用及其 如何影响上下文。 下面将分别对各种函数调用方式分析this的指向。

2、函数调用

2.1 什么是函数调用

函数调用=函数名(参数),比如add(1,2),函数调用表达式不能是属性方式的调用。我们来看看以下两种函数调用方式,有一个直观的认识

1、 最简单的函数调用demo

function add(a, b) {
  return a + b;
}
//函数调用
const result = add(1,2)
console.log(result); // => 3

1、 立即调用的函数表达式(IIFE)

const result = (function add(a, b) {
  return a + b;
})(1,2)//函数调用
console.log(result); // => 3

2.2 函数调用中的this

在函数调用中,执行上下文是全局对象。在浏览器中(本文默认代码最终在浏览器运行),this是 window 对象。

75_2.png

  • 看个demo

在函数作用域内调用

function add(a, b) {
   console.log(this === window); // => true
   this.number = 20; // 将'number'属性添加到全局对象
   return a + b;
}
add(1, 2);     // => 3
console.log(window.number); // => 20

在函数作用域外调用

console.log(this === window); // => true
this.testStr = 'Hello World!';
console.log(window.testStr); // => 'Hello World!'

2.3 严格模式下的函数调用 this

使用’use strict’的时候,this为undefined

75_3.png

  • 看个demo
function add(a, b) {
  'use strict'; // 启用严格模式
  console.log(this === undefined); // => true
  return a * b;
}
add(2, 5); // => 10

因此单个JS文件可能包含严格和非严格模式

2.4 总结

当函数独立调用的时候,在严格模式下它的this指向undefined,在非严格模式下,当this指向undefined的时候,自动指向全局对象(浏览器中就是window)

2、 方法调用

2.1 什么是方法调用

简单来说就是对象中的某个方法,我们通过对象来调用某个方法时就是方法调用,方法调用需要一个属性访问器形式来调用函数。

  • 看几个简单的方法调用demo
const calculate = {
  add: function(){
    console.log(this);  //Object{value: 1, add: ƒ}
    this.value += 1;
  }
}
calculate.add(); // 方法调用
['Hello', 'World'].join(', '); // 方法调用

const otherFunction = calculate.add;
otherFunction();     // 函数调用      

otherFunction需要特别注意,这种形式的调用是属于函数调用,不要弄错了,这种情况属于方法和对象分离,我们具体来看看

  • 方法与对象分离
    方法可以从对象中提取到一个单独的变量const otherFunction = calculate.add,当方法单独调用时,与原始对象分离,此时的this指向全局对象window
function calculate() {
  this.add = function() {
    console.log(this === calculate); // => false
    console.log(this) // => [object Window]
  }
}
const cal = new calculate();
setTimeout(cal.add, 1000);

setTimeout(cal.add, 1000);等价于以下代码

const add = cal.add;
setTimout(add);

  • 解决方案
    • bind():方法与对象绑定cal.add.bind(cal)
    • add改为箭头函数

2.2 方法调用中 this 是肿么样

75_4.png可以看出this指向调用者,下面看几个实际的demo

const calculate = {
  num: 0,
  add: function() {
    console.log(this === calculate); // => true
    this.num += 1;
    return this.num;
  }
};
calculate.add(); // => 1
calculate.add(); // => 2

3、构造函数调用

3.1 什么是构造函数调用

new关键词紧接着函数对象,执行的是构造函数调用,比如new calculate()

es6之后我们可以用class关键词结合constructor来定义构造函数,当然也可以使用function来定义构造函数

  • function构造函数
function calculate(){
    this.x = '1';
    this.y = function(){};
}
var cal = new calculate();//构造函数调用

  • class构造函数
class calculate {
  constructor(number1, number2) {
    this.number1 = number1;
    this.number2 = number2;
  }
}
var cal = new calculate(1,2);//构造函数调用

3.2 构造函数中的 this

75_5.pngnew calculate() 正在进行构造函数调用,其中上下文是cal。 在calculate内部初始化对象:this.property被赋值为默认值。

class calculate {
  constructor() {
    console.log(this instanceof calculate); // => true
    this.property = 'Default Value';
  }
}
const cal = new calculate();
cal.property; // => 'Default Value'

3.3 new做了些啥

如果函数作为构造函数掉用,那么其中的this就代表它即将new出来的对象,主要有几个步骤

  • 创建一个临时对象
  • 给临时对象绑定原型
  • 给临时对象对应属性赋值
  • 将临时对象return

4、 隐式调用

4.1 什么是隐式调用

使用calculte.call()或calculte.apply()方法调用函数时,执行的是隐式调用

  • call和apply区别
    • 本质上讲都是动态的改变this上下文,
    • 第一个参数都是,指定函数体内this的指向
    • 第二个参数开始不同,apply是数组或者类数组
    • call比apply的性能要好,平常可以多用call
方法 .call(thisArg[, arg1[, arg2[, ...]]])将接受的第一个参数thisArg作为调用时的上下文,arg1, arg2, ...这些则作为参数传入被调用的函数。
方法.apply(thisArg, [args])将接受的第一个参数thisArg作为调用时的上下文,并且接受另一个类似数组的对象[arg1, arg2, ...]作为被调用函数的参数传入

4.2 隐式调用中的this

75_6.png下面看下实际的列子

const obj = {name: "test"}
function calculate(){
   console.log(this === obj); // => true
   return  this.name;
}
console.log(calculate.call(obj))//  => "test"

5、绑定函数bind

5.1 什么是绑定函数

与.apply()和.call() 方法不同,它不会立即调用该函数,.bind()方法只返回一个新函数,在之后被调用,只是this已经被提前设置好了

bind语法: func.bind(thisArg[, arg1[, arg2[, …]]])
1、thisArg 当绑定函数被调用时,该参数会作为原函数运行时的this指向。当使用 new 操作符调用绑定函数时,该参数无效。
2、arg1, arg2, … 当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。

  • 使用方式大概如下:
const newFn = fn.bind(thisObj);
newFn(arg1, arg2...)

5.2 bind中this的指向

75_7.png

  • demo
var obj = {};
function calculate() {
    console.log(this === obj);
}
var testObj = calculate.bind(obj);
testObj();  //true

.bind()创建一个永久的上下文链接,并始终保持它。 一个绑定函数不能通过.call()或者.apply()来改变它的上下文

6、箭头函数

在了解箭头函数之前,我们先回顾下常规函数的写法

function test(name) {  //声明式写法
    console.log(name)
}

let test2 = function(name) {  //赋值式写法
    console.log(name)
}

6.1 什么是箭头函数

ES6新增了箭头函数,用于以更短的形式声明函数,并在词法上绑定上下文,但是箭头函数有几个规则

  • 规则一:箭头函数只能用赋值式写法,不能用声明式写法
  • 规则二:如果参数只有一个,可以不加括号,如果没有参数或者参数多于一个就需要加括号
const test = name => {
    console.log(name)
}
const test2 = (name1, name2) => {
    console.log(name1 + ' and ' + name2)
}

  • 规则三:如果函数体只有一句话,可以不加花括号
const test = name => console.log(name) 

  • 规则四:如果函数体没有括号,可以不写return,箭头函数会帮你return
const test = (p1, p2) => p1 + p2

  • 规则五:箭头函数不能用作构造函数

6.2 箭头函数中的this

箭头函数不会创建自己的执行上下文,而是从定义它的外部函数中获取 this。 换句话说,箭头函数由外部来决定this的指向。

75_8.png来看几个demo

  • 箭头函数在函数作用域时的this
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  log() {
    console.log(this === myPoint); // => true
    setTimeout(()=> {
      console.log(this === myPoint);      // => true
      console.log(this.x + ':' + this.y); // => '95:165'
    }, 1000);
  }
}
const myPoint = new Point(95, 165);
myPoint.log();

  • 箭头函数在顶层作用域时的this
    以下函数在顶层作用域,this指向的是window
const getContext = () => {
   console.log(this === window); // => true
   console.log(this); // =>[object Window]
};
getContext() 

7、 问题思考和解答

7.1 函数嵌套时this的指向

const calculate = {
   number1: 5,
   number2: 10,
   sum: function() {
     console.log(this === calculate); // => true
     function add() {
       console.log(this === calculate); // => false
       return this.number1 + this.number2;
     }
     return add();
   }
};
calculate.sum(); 

  • ❓思考:上面add方法中this的指向是什么?
    内部函数的上下文只依赖于它的调用类型,而不依赖于外部函数的上下文,add()是一个函数调用,它将this作为全局对象window(非严格模下)。所以this指向window

8、总结

之前对javascript一知半解,现在重新来学习,这是写的第一篇前端文章,有问题欢迎指出

75_9.png参考文章:

文章永久链接:https://tech.souyunku.com/31635

未经允许不得转载:搜云库技术团队 » 入门JavaScript中的this指向(ES6)

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们