当前位置: 首页 > 游戏攻略> 正文

深入理解JavaScript中this指向的问题

来源:网络 作者:趣玩小编 发布时间:2024-07-03 18:48:33

最近在回顾JavaScript的面试题,this指向是前端开发中必须掌握的知识点。随着ES6+时代的到来,箭头函数的出现使得我们有必要重新梳理JavaScript中this指向的问题。

在了解this指向的问题前,首先需要明确JavaScript是一种具有函数优先的轻量级、解释型或即时编译型的编程语言。它基于原型编程、多范式的动态脚本语言,并支持面向对象、命令式、声明式、函数式编程范式、闭包、基于原型的继承等高级功能。

在面向对象语言中,this表示当前对象的一个引用。然而在JavaScript中,this并非固定不变,它会随着执行环境的改变而改变。在方法中,this表示该方法所属的对象;如果单独使用,this表示全局对象;在函数中,this同样表示全局对象;而在严格模式下,this是未定义的(undefined);在事件中,this表示接收事件的元素;此外,类似call()和apply()方法可以改变this的指向,引用到任何对象。因此,this的指向完全取决于函数的调用方式。

接下来,我将通过下面的例图和例子(非严格模式下)来解析this的指向:

1.不使用new关键字,使用dot调用:

var obj = {
    name: 'bug',
    obj2: {
           name: 'bug2',
           fn: function () {
                console.log(this.name); //bug2
           }
     }
}
//通过obj.obj2.fn()调用obj中的obj2中的fn函数,此时fn函数中this的指向为dot (.) 前面的对象,即为obj2,obj2中的name即是bug2。
obj.obj2.fn();

2.使用new关键字调用:

function fn() {
  this.x = 1;
}

//通过new关键字生成了一个实例对象,此时的this指向了该实例对象fn
var obj = new fn();

//此时的obj的结构为{x:1},所以obj.x=1
obj.x // 1

讲到new关键字就引出了另一个关键点,如果使用new去创建一个实例对象,实例对象有返回值呢?通常情况下是不应该有显式的返回值的。但是如果return返回的是一个对象,那么将返回该对象。以下通过几个例子验证这一点:

①return空对象:

function fn() 
{ 
   this.name= 'bug'; 
   //此处return回了一个对象
   return {}; 
}
var obj = new fn(); 
//因为return回的是一个对象,所以此时的obj的结构是返回的空对象{},所以obj.name才会是undefined
console.log(obj.name); //undefined

②return一个非空对象:

function fn() 
{ 
   this.name= 'bug'; 
   //此处return回了一个非空对象
   return {name:'bug2'}; 
}
var obj = new fn(); 
//因为return回的是一个非空对象,所以此时的obj的结构是返回的非空对象{name:'bug2'},所以obj.name是bug2
console.log(obj.name); //bug2

③返回数字:

function fn() 
{ 
   this.name= 'bug'; 
   //此处return回了一个数字
   return 11; 
}
var obj = new fn(); 
//因为return回的是一个数字,所以此时返回的实例对象不受影响,结构是{name:'bug'},所以obj.name是bug
console.log(obj.name); //bug

④返回字符串:

function fn() 
{ 
   this.name= 'bug'; 
   //此处return回了一个字符串
   return 'xxxxx'; 
}
var obj = new fn(); 
//因为return回的是一个字符串,所以此时返回的实例对象不受影响,结构是{name:'bug'},所以obj.name是bug
console.log(obj.name); //bug

随着进入了Es6+的时代,我们需要了解箭头函数的this指向:

1.什么是箭头函数:

箭头函数是ECMAScript 6中新增的一种函数定义方式,也被称为Lambda函数。 它使用箭头(=>)符号来替代传统的function关键字,从而更简洁地定义函数,使代码更加简洁易读。箭头函数的特点有:语法简洁,不绑定自己的this,没有arguments对象,不能用作构造器。

2.箭头函数的this指向:

箭头函数不绑定自己的this,它会捕获定义时所在上下文的this值。因此,箭头函数没有属于自己的this。下面通过例子来说明:

①正常function函数:

const obj={
      mythis: function(){
           console.log(this) //指向了上一级对象obj
      }
}
obj.mythis() //返回了obj对象

②箭头函数:

const obj={
     mythis: ()=>{
          console.log(this) //因为箭头函数没有自己的this,所以指向的是window
     }
}
obj.mythis() //返回了window

此外,通过call、apply、bind也可以强制改变this的指向。具体如下:

1.什么是call:call方法可以接受两个参数,第一个参数是this的指向,第二个参数为参数列表。当第一个参数为null或undefined时,this默认指向window。

function fn(...args) {
    console.log(this, args);
}
let obj = {
    name: "bug"
}
fn.call(obj, 1, 2); //{name:'bug'} , [1,2]
fn(1, 2) //window , [1,2]
fn.call(null,[1,2]);//window , [1,2]
fn.call(undefined,[1,2]);//window , [1,2]

2.什么是apply:apply方法可以接受两个参数,第一个参数是this的指向,第二个参数为一个参数数组。当第一个参数为null或undefined时,this默认指向window。

function fn(...args) {
    console.log(this, args);
}
let obj = {
    name: "bug"
}
fn.apply(obj, [1,2]); //{name:'bug'} , [[1,2]]
fn([1,2]) //window , [[1,2]]
fn.apply(null,[1,2]);//window ,  [[1,2]]
fn.apply(undefined,[1,2]);//window , [[1,2]]

3.什么是bind:bind方法跟call、apply十分相似,第一个参数也是this的指向,第二个参数传的也是一个参数列表,但是这个参数列表可以分多次传入。而且改变完this的指向并不会立刻执行,而是返回一个已经永久改变this指向的函数。

function fn(...args) {
     console.log(this, args);
}
let obj = {
     name: "bug"
}
const bindFn = fn.bind(obj); //this变为obj,且不会立马执行
bindFn(1, 2) //通过调用才会执行,并传入参数列表1,2,最终this指向obj {name:'bug'}
fn(1, 2) //this执行window

以上是call、apply、bind的区别:

①三者都可以改变函数的this对象指向

②三者第一个参数都是this要指向的对象,如果没有这个参数或参数为 undefined 或 null,则默认指向全局 window

③三者都可以传参,但是apply是数组,而call是参数列表。apply和call是一次性传入参数,而bind可以分为多次传入,并且bind是返回绑定this之后的函数,apply、call则是立即执行

综上所述,this的指向并非固定不变,它会随着执行环境的改变而改变,具体如何改变完全取决于函数的调用方式。箭头函数没有属于自己的this,作为方法的箭头函数this的指向是当前的上下文。希望以上内容对您有所帮助。本文为个人学习整理内容,水平有限,如有错误之处,欢迎指正!

相关攻略 更多 +
玩家最喜欢 更多 +
热门攻略 更多 +
热搜
查看完整榜单