JavaScript基础系列(6):`this`这六种使用方式,你都理解了吗?

简介: 执行发现两个this都指向了全局的window.也就是全局执行上下文中的this和函数执行上下文中的this都指向了全局window.所以默认的情况下,在全局中调用一个函数,函数中执行上下文中的this都是指向window对象的。

image.png


上个月写过一篇V8是如何运行JavaScript(let a = 1)代码的?,写完之后我就发现,我对平常使用的工具V8引擎,偏底层的知识了解的竟然是如此甚少。同时我真正从事前端的时间还算是比较短的,那么基础也算是非常的薄弱。结合以上,我打算有时间就去从底层的角度去学习了解,便于在使用过程中的理解和解决遇到的问题,理解JavaScript的本质,能够更好的学习JavaScript。如果你跟我有同样的困惑,那我们可以结伴同行,共同学习。


本系列我会从我的视角不断的去总结:








1、前言


通过本文可以学习到以下三点:


  • 了解严格模式和非严格模式的区别


  • 了解this在不同场景下的区别


  • 了解如何改变this的指向问题


2、普通函数


<script>
console.log(this, '全局')
function foo() {
  console.log(this, '函数')
}
foo()
</script>

image.png


执行发现两个this都指向了全局的window.也就是全局执行上下文中的this和函数执行上下文中的this都指向了全局window.所以默认的情况下,在全局中调用一个函数,函数中执行上下文中的this都是指向window对象的。


而我们平常工作中的项目,你可以去试试通常都是严格模式下的。


在ECMAscript 5的时候,JavaScript引擎添加了另外一种运行模式:严格模式,这种情况下代码会在更严格的条件下运行。而我们上面的代码其实就是运行在非严格模式下,我只是在一个html文件中添加如上代码,没有其他任何的设置配置。而我们平常工作中的项目,你可以去试试通常都是严格模式下的。


我们来看上面的代码如何在严格模式下运行。


<script>
"use strict"
console.log(this, '全局')
function foo() {
  console.log(this, '函数')
}
foo()
</script>


image.png


可以发现,函数中的this打印,变成了undefined。在全局调用一个函数执行,其函数执行上下文中的this值是undefined。


总结:全局上下文中的this,无论在严格模式还是非严格模式下,它的指向都是全局变量window。 普通函数中的this,在严格模式下的指向是undefined,在非严格模式下的指向为全局变量的window。


3、var和let声明的变量


<script>
console.log(this, '全局')
var name1 = 'name1'
let name2 = 'name2'
console.log(this.name1, '全局this.name1')
console.log(this.name2, '全局this.name2');
function foo() {
  console.log(this, '函数')
  console.log(this.name1, '函数this.name1')
  console.log(this.name2, '函数this.name2');
}
foo()
</script>

image.png


通过运行可以发现通过let声明的变量,无论是在全局执行上下文,还是函数执行上下文中打印的都是undefined。


总结:通过执行上下文的角度,我们去查看过var和let声明变量的区别,有兴趣的可以去查看一下( www.baidu.com )。var声明的变量被存放到执行上下文的变量环境,let声明的变量都被存放到执行上下的词法环境中,但是var声明的变量同时被存放到全局变量window下,而全局执行上下文中的this指向是window。而let不在其中,所以无论是全局执行上下文还是函数执行上下,this中是访问不到let声明的变量的。


4、对象中的函数


<script>
  'use strict';
let bar = {
  name: 'aehyok',
  fun: function () {
    console.log(this.name,'bar对象')
  }
}
bar.fun()
const bb = bar.fun
bb()
</script>


image.png


通过截图执行情况可以发现,在严格模式下,直接调用bar.fun()打印出来的this指向的是bar对象。如果将bar.fun赋值给一个变量,这个变量的引用其实存储的就是bar对象中的fun函数,这样相当于变成了一个普通的函数,在严格模式下打印出来就为undefined。


总结:使用对象来调用其内部的一个函数,该函数的this指向为对象本身。在全局上下文中调用一个函数,函数内部的this指向为(严格模式下指向undefined,非严格模式下指向为window)


那调用bb()的时候有没有办法将this指向原来的bar对象呢?


5、call、apply、bind


<script>
  'use strict';
let bar = {
  name: 'aehyok',
  fun: function () {
    console.log(this,'bar对象')
  }
}
bar.fun()
const bb = bar.fun
bb()
bar.fun.call(bar)
bar.fun.apply(bar)
bar.fun.bind(bar)()
</script>


image.png


通过截图的执行结果可以发现,最后三个的打印this指向全部是bar对象本身。再看最后三行代码,call、apply、bind,都可以改变函数的this指向。


6、箭头函数


<script>
  'use strict';
let bar = {
  name: 'aehyok',
  fun:function() {
    console.log(this,'bar函数')
    function inner () {
      console.log(this, 'inner函数')
    }
    inner()
  }
}
bar.fun()
</script>


image.png


通过之前的解析我们可以非常的清楚,如截图所示的执行结果。在fun函数中的this指向为bar对象,而在inner函数中调用的this指向为undefined。这里也就说明了嵌套函数里的this并不会传递,并不会将我们能否将this指向改为bar对象呢?当然上一小节,我们已经可以通过call、apply、bind改变this的指向。


第一种方式:通过定义变量进行传递this


<script>
  'use strict';
let bar = {
  name: 'aehyok',
  fun:function() {
    console.log(this,'bar函数')
    let self = this
    function inner () {
      console.log(self, 'inner函数')
    }
    inner()
  }
}
bar.fun()
</script>


image.png


定义一个self变量,如果嵌套函数inner中需要,在inner函数中直接使用self,而不是this了。


这里我们来看一下另外一种方式:箭头函数的妙用


<script>
  'use strict';
let bar = {
  name: 'aehyok',
  fun:function() {
    console.log(this,'bar函数')
    let inner = () => {
      console.log(this, 'inner函数')
    }
    inner()
  }
}
bar.fun()
</script>


image.png


通过运行的截图可以发现,inner箭头函数中this的指向是bar对象。这是因为ES6中的箭头函数并不会创建自身的执行上下文,所以箭头函数中的this取决于它的外部函数。那么很自然的就指向了bar对象了。


7、构造函数


还是通过vue创建实例来看结果


<script>
  // "use strict"
function Vue (name) {
  let vm = this
  vm.name = name
  console.log(vm)
}
const _vue = Vue('普通函数')
const vue = new Vue('构造函数')
</script>


执行结果如下


image.png


总结:

_vue通过普通函数赋值,其中的this指向指向了window(这里是非严格模式)。

如果是严格模式this指向会是undefined。

而通过构造函数new出来,其中的this指向了构造函数创建出来的实例对象。这也是构造函数比较特殊的地方。


8、总结


  • 1、全局执行上下文中的this


  • 在严格模式下和非严格模式下,this的指向都为全局变量window。


  • 2、函数执行上下文中的this(在全局执行上下文中调用函数)


  • 在非严格模式下,this的指向为全局变量window。


  • 在严格模式下,this的指向为undefined。


  • 3、通常我们在项目中都是在严格模式下调用的,当然也有配置可配。(你可以在公司的vue项目中进行测试)


  • 4、对象中的函数


  • 通过对象.函数的方式,this的指向便是对象本身


  • 但是要注意不能将对象.函数赋值给别的变量,然后再调用额


  • 5、构造函数


  • 通过构造函数 new 出来的,其中的this指向了new出来的实例对象


  • 6、改变 this 指向的方式


  • 通过箭头函数


  • 通过声明 let self = this,然后在需要的嵌套函数中使用self 即可


  • 就是使用 call apply bind


  • fun.apply(thisArgs, [arg1, arg2]) 参数通过数组的方式传递
  • fun.call(thisArgs, arg1, arg2) 参数通过多个参数传递
  • fun.bind(thisArgs, arg1, arg2)() bind 相当于创建一个新的函数,我们还需要手动调用
目录
相关文章
|
JavaScript 前端开发
javascript中的this
javascript中的this
|
JavaScript
JS中改变this指向的六种方法
JS中改变this指向的六种方法
|
自然语言处理 JavaScript 前端开发
在JavaScript中,this关键字的行为可能会因函数的调用方式而异
【6月更文挑战第15天】JavaScript的`this`根据调用方式变化:非严格模式下直接调用时指向全局对象(浏览器为window),严格模式下为undefined。作为对象方法时,`this`指对象本身。用`new`调用构造函数时,`this`指新实例。`call`,`apply`,`bind`可显式设定`this`值。箭头函数和绑定方法有助于管理复杂场景中的`this`行为。
115 3
|
JavaScript 前端开发
js中改变this指向、动态指定函数 this 值的方法
js中改变this指向、动态指定函数 this 值的方法
|
自然语言处理 JavaScript 前端开发
在JavaScript中,this关键字的行为可能会因函数的调用方式而异
【5月更文挑战第9天】JavaScript中的`this`关键字行为取决于函数调用方式。在非严格模式下,直接调用函数时`this`指全局对象,严格模式下为`undefined`。作为对象方法调用时,`this`指向该对象。用`new`调用构造函数时,`this`指向新实例。通过`call`、`apply`、`bind`可手动设置`this`值。在回调和事件处理中,`this`可能不直观,箭头函数和绑定方法可帮助管理`this`的行为。
109 1
|
JavaScript 前端开发
深入探索JavaScript:如何改变this的指向
深入探索JavaScript:如何改变this的指向
176 2
|
JavaScript 前端开发
【专栏】`Function.prototype.apply` 在JavaScript中用于动态设定函数上下文(`this`)和参数列表
【4月更文挑战第29天】`Function.prototype.apply` 在JavaScript中用于动态设定函数上下文(`this`)和参数列表。它接受两个参数:上下文对象和参数数组。理解`apply`有助于深入JS运行机制。文章分三部分探讨其原理:基本概念和用法、工作原理详解、实际应用与注意事项。在应用中要注意性能、参数类型和兼容性问题。`apply`可用于动态改变上下文、传递参数数组,甚至模拟其他语言的调用方式。通过深入理解`apply`,能提升代码质量和效率。
189 3
|
JavaScript
js 【详解】函数中的 this 指向
js 【详解】函数中的 this 指向
154 0
|
JavaScript 前端开发 数据安全/隐私保护

热门文章

最新文章