JavaScript当中的this指向的全解

想必大家在编程当中见过不少的this,对this 的指向也是非常的头疼,所以在这里我总结了几种常见的情况,希望对各位读者有所帮助😄

全局上下文的this

全局上下文,也就是this在全局作用域下,此时的this相当于window

conso.log(this)
// 此时在控制台中打印的结果是 window
if (this === window) {
    console.log('yes')
  } else {
    console.log('no')
  }
// 这时候打印的也是符合预期的 yes

在这里插入图片描述

为了让大家有更深刻的理解,这里再次做一个测试

this.userName = "zhangsan";
window.age = 18;

console.log(this.age); // 输出 18
console.log(window.userName); // 输出 'zhangsan'

这是因为给 this 添加属性,就相当于给 window 添加属性,给 window 添加属性,就相当于给 this 添加属性,也再一次验证了this在全局作用域下相当于window

全局上下文中的函数

函数上下文中的 thisarguments 一样,就是函数的隐式参数,可以在任意函数中调用,它的指向不是固定不变的,取决于函数处于什么位置、以什么方式调用

直接调用函数

function fn1() {
  console.log(this); 
}
fn1();
// 调用的结果会输出 window
// 此时函数的调用相当于 window.fn1();

function fn2() {
  let a = 1;
  console.log(this.a); // 输出 2
}
var a = 2;
fn2();
// 此时函数的调用相当于 window.fn2();

注意:利用 var 声明的变量会有变量提升

总结函数当中的this指向的是函数的调用者,在全局上下文当中的函数的调用者实际是 window。由于是在全局上下文当中的函数,所以调用函数时可以省略 window,也就是我们通常所见到的 函数名 ();形式的函数调用方式。

在严格模式下全局上下文中的函数
function fn() {
  "use strict"; // 代表开启了严格模式,此时代码的检查会变得非常严格
  console.log(this); // 输出 undefined
}
fn();

对象中的函数

对象当中的函数也称之为对象的方法,而方法的调用者也就是这个方法的拥有者,也就是对象

全局上下文中的对象

const obj = {
  age: 18,
  fn() {
    console.log("this是:", this); // 输出    this是:obj
    console.log("this.age是:", this.age); // 输出    this.age是:18
  },
};

obj.fn();

在这里插入图片描述

此时对像当中的函数的 this 指的依旧是函数的调用者,也就是 fn(); 的调用者,而对象调用了这个函数 obj.fn();

所以此时 this === obj

const obj = {
  age: 18,
  fn() {
    console.log('this是:', this) // 输出 this是:obj
    console.log('this.age是:', this.age) // 输出 this.age是:18
    if (this === obj) {
      console.log('yes')
    } else {
      console.log('no')
    }
  }
}

obj.fn()

在这里插入图片描述

所得结果符合预期。

函数嵌套有函数

const obj = {
  age: 18,
  fn() {
    return function () {
      console.log("this是:", this); // 输出 this是:window
      console.log("this.age是:", this.age); // 输出 this.age是:100
    };
  },
};

var age = 100;

obj.fn()();

其实我们可以这样理解

obj.fn()();

// 等价于

const temp = obj.fn(); // 定义一个临时变量来存储 obj.fn 返回的函数
temp(); // 执行这个函数

其实单独的 obj.fn();也不会报错,但是返回的不再是原始类型的数据了,而返回的是一个引用类型的数据 ,在这里返回的其实是一个函数,而this在返回的函数里面使用的,那么this指向的是返回的函数的调用者。

在这里插入图片描述

函数嵌套有箭头函数

但是在有时候我们就想在函数嵌套有函数的情况下让this指向的就是obj,那么可以使用箭头函数

const obj = {
  age: 18,
  fn() {
    return () => {
      console.log("this是:", this); // 输出 this是:obj
      console.log("this.age是:", this.age); // 输出 this.age是:18
    };
  },
};

obj.fn()();

对于普通函数来说,内部的 this 指向函数运行时所在的对象。

对于箭头函数,它不会创建自己的 this,它只会从自己的作用域链的上一层继承 this

所以这里 fn 中嵌套的匿名箭头函数中的 this,指向它作用域链的上一层的 this,也就是函数 fnthis,也就是 obj

构造函数

this 指向新建的实例

function Person(name) {
  this.name = name;
}
const p = new Person("zhangsan");
console.log(p.name); // 'zhangsan'

这里的this指向的是利用Person 这个构造函数 new 出来的实例,也就是 p

代码执行后, this.name = name; 也就意味着 为实例 p 当中的name 属性赋值zhangsan

构造函数内的返回值是一个对象

示例代码:

function Person(name) {
  this.name = name;
  return {
    name: "syh",
  };
}
const p = new Person("zhangsan");
console.log(p.name); // 'syh'

这里我们先打印一下 p 看看结果

在这里插入图片描述

到这里,我们先看看 new Person();究竟做了什么。

第一步: 创建一个Object对象实例。
第二步: 将构造函数的执行对象(也就是构造函数当中的所有代码)赋给新生成的这个实例。
第三步: 执行构造函数中的代码(构造函数当中的代码可能会给实例添加属性或者方法)
第四步: 将执行的结果返回给新生成的对象实例

就结果而言,只要new 构造函数(); 就会自动的返回一个已经处理好对象

在示例代码当中Person这个构造函数出现了return {name: "syh"};返回的是一个人为设置的对象,那么就会将那个自动生成的对象给覆盖掉,这也就是为什么 p = {name: "syh"}; 而不是 p = {name: "zhangsan"}; 的原因。所以最后打印的就是 {name: "syh"} 对象当中 name 属性所对应的,也就是 syh

简单总结: 如果构造函数当中有 return 且 return 复杂类型;(对象也是复杂类型的一种) 则 new 构造函数(); 返回的是那个手动设置的那个复杂类型。

return 返回的是一个原始值(简单类型)

function Person(name) {
  this.name = name;
  return 123;
}
const p = new Person("zhangsan");
console.log(p.name); // 'zhangsan'

return 简单类型; 的时候,this依旧指向的是那个自动生成的对象

显式改变函数上下文的 this

call()

Function.prototype.call() ,这里出现了Function.prototype ,那么就意味着只要是函数,那么基本上都可以使用 call(); 这个方法。Function 可以简单的理解为所有函数的父级函数prototype 指向原型对象,那么连起来就是Function.prototype.call(); Function这个函数的原型上挂载一个call方法

示例代码:

function fn() {
  console.log(this.name)
}
const obj = {
  name: 'zhangsan'
}
var name = '我是 window 下的 name'
fn() // 输出 '我是 window 下的 name'
fn.call(obj) // 指定 this 为 obj,输出 'zhangsan'

在这里插入图片描述

调用fn.call(obj);改变了原先的this 指向 ,将this指向手动的修改为了 obj 并且调用了fn函数

apply()

Function.prototype.apply() 那么就意味着只要是函数,那么基本上都可以使用 apply(); 这个方法。

按作用效果来说的话,apply() 方法与 call() 方法一样,都会改变函数的this 指向并调用函数。区别只是只是传参形式不一样,call 是传多个参数,apply 是只传参数集合

示例代码:

function add(x, y, z) {
  let result = this.x + this.y + this.z
   console.log(result);
}

const obj = {
  x: 1,
  y: 2,
  z: 3
}

add.call(obj, 1, 2, 3) // 输出 6
add.apply(obj, [1, 2, 3]) // 输出 6,只是传参形式不同而已,传入的参数是一个数组,也就是数据的集合

在这里插入图片描述

bind()

Function.prototype.bind() 那么就意味着只要是函数,那么基本上都可以使用 bind(); 这个方法。

如果函数调用了 bind() 方法,那么就会创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。也就意味着 函数1.bind() ,这个函数1并不会被自动调用。

function add(x, y, z) {
  let result = this.x + this.y + this.z
  console.log(result)
}

const obj = {
  x: 1,
  y: 2,
  z: 3
}
add() // undefined 之间相互运算,所得结果是 NaN 
const add1 = add.bind(obj) // bind 会返回一个新的函数
add1() // 执行新的函数,输出 6

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

读书的小蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值