放肆青春的博客
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)

放肆青春

一个前端菜鸟的技术成长之路
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)
  • 前端

    • 前端 概览
    • 前端汇总

    • front 博文

    • front 项目总结

    • front 高级

    • front tools

  • vue

    • vue 概览
    • vue 汇总

    • vue 博文

    • vue 项目总结

    • vue 高级

  • html

    • html 概览
    • html 汇总

    • html 博文

  • css

    • css 概览
    • css 汇总

    • css 博文

    • sass

    • less

  • js

    • javascript 概览
    • JS 汇总

    • ES6

    • JS 博文

      • js 基础语法
      • js 数据类型
      • js 字符串
      • js 数组
      • js 对象
      • js 变量
      • js 函数
      • js 事件
      • js 循环
      • js 浅拷贝和深拷贝
      • js 动画
      • js DOM
      • js 防抖节流
      • js 原型及原型链
      • js this
        • 全局上下文
        • 函数上下文
          • this 的 4 种指向
          • this 的四种绑定规则
          • 普通函数改变 this 指向
          • 箭头函数 this 指向
      • js 作用域
      • js 继承
      • js 闭包
      • js 内存
      • js垃圾回收
    • JS 工具

  • node

    • node 概览
    • node 汇总

    • node 框架

    • node 博文

  • react

    • react 概览
    • react 汇总

    • react 博文

    • react 高级

  • 微信小程序

    • 微信小程序 概览
    • 微信小程序总结
    • 微信小程序文章
    • 微信小程序 博文

    • 微信小程序 高级

  • 微信公众号

    • 微信公众号 概览
    • 微信公众号总结
    • 微信公众号文章
  • 多端开发

    • 多端开发
    • dsbridge 概览
    • jsbridge 概览
    • webview
    • uniapp

      • uniapp 概览
    • taro

      • taro 概览
    • flutter

      • flutter 概览
      • flutter 环境搭建
    • electron

      • electron 概览
  • front
放肆青春
2021-03-22

js this

在函数中 this 到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了

this 就是指针,指向我们调用函数的对象

普通函数:谁调用(this)就指向谁。

# 全局上下文

在全局执行上下文中(在任何函数体外部)this 都指代全局对象,浏览器的全局对象是 window。

// 在浏览器中, window 对象同时也是全局对象:
console.log(this === window); // true

this.name = "yz";
console.log(window.name); // "yz"
console.log(name); // "yz"
1
2
3
4
5
6

# 函数上下文

在函数内部,this 的值取决于函数被调用的方式。

this 绑定的优先级:

new 绑定(构造函数调用) > 显示绑定(call 和 apply 调用) > 隐式绑定(对象方法调用) > 默认绑定(普通函数调用)

# this 的 4 种指向

  1. 作为函数调用,非严格模式下,this 指向 window,严格模式下,this 指向 undefined;

  2. 作为某对象的方法调用,this 通常指向调用的对象。

  3. 在构造函数中,this 指向新创建的对象

  4. 箭头函数没有单独的 this 值,this 在箭头函数创建时确定,它与声明所在的上下文相同。

使用 apply、call、bind 可以绑定 this 的指向。

# this 的四种绑定规则

默认绑定、隐式绑定、显示绑定、new 绑定。优先级从低到高

# 默认绑定(作为普通函数被调用)

没有其他绑定规则存在时的默认规则

当函数不作为对象的属性被调用时候,也就是我们所说的普通函数方式,此时的 this 总是指向全局的对象。在浏览器的 js 里面,这个全局对象是 window 对象。

function foo() {
    console.log( this.a );
}
var a = 2;
foo() ==== foo.call(window) // 2
1
2
3
4
5

因为 foo()是直接调用的(独立函数调用),没有应用其他的绑定规则,这里进行了默认绑定,将全局对象绑定 this 上,所以 this.a 就解析成了全局变量中的 a,即 2。

function foo() {
  "use strict";
  console.log(this.a);
}

var a = 2;
foo(); // Uncaught TypeError: Cannot read property 'a' of undefined
1
2
3
4
5
6
7

注意:在严格模式下(strict mode),全局对象将无法使用默认绑定,即执行会报 undefined 的错误

# 隐式绑定(作为对象的方法调用)

除了直接对函数进行调用外,有些情况是,函数的调用是在某个对象上触发的,即调用位置上存在上下文对象。

当函数作为对象的方法被调用的时候,this 指向该对象

function foo() {
  console.log(this.a);
}

var a = 2;

var obj = {
  a: 3,
  foo: foo,
};

obj.foo(); // 3
1
2
3
4
5
6
7
8
9
10
11
12

对 foo 的调用存在上下文对象 obj,this 进行了隐式绑定,即 this 绑定到了 obj 上,所以 this.a 被解析成了 obj.a,即 3。

多层调用链

function foo() {
  console.log(this.a);
}
var obj2 = {
  a: 2,
  fn: foo,
};
var obj1 = {
  a: 1,
  o1: obj2,
};
obj1.o1.fn(); // 2
1
2
3
4
5
6
7
8
9
10
11
12

如果是链性的关系,比如 xx.yy.obj.foo();, 上下文取函数的直接上级,即紧挨着的那个,或者说对象链的最后一个。

obj1 对象的 o1 属性值是 obj2 对象的地址,而 obj2 对象的 fn 属性的值是函数 foo 的地址; 函数 foo 的调用环境是在 obj2 中的,因此 this 指向对象 obj2;

# 显示绑定

通过这两个方法 call(…)或 apply(…)来实现

function foo() {
  console.log(this.a);
}

var a = 2;

var obj1 = {
  a: 3,
};

var obj2 = {
  a: 4,
};
foo.call(obj1); // 3
foo.call(obj2); // 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# new 绑定(构造函数调用)

通常情况下,构造器里面的 this 就是指向返回的这个对象

  1. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
function foo(a) {
  this.a = a;
}

var a = 2;

var bar1 = new foo(3);
console.log(bar1.a); // 3

var bar2 = new foo(4);
console.log(bar2.a); // 4
1
2
3
4
5
6
7
8
9
10
11

每次调用生成的是全新的对象,该对象又会自动绑定到 this 上

  1. 如果原函数返回一个对象类型,那么将无法返回新对象,将丢失绑定 this 的新对象。
function foo() {
  this.a = 10;
  return new String("捣蛋鬼");
}
var obj = new foo();
console.log(obj.a); // undefined
console.log(obj); // "捣蛋鬼"
1
2
3
4
5
6
7

# 普通函数改变 this 指向

call、apply 和 bind 都是用于改变函数运行时内部 this 的指向的

# apply

应用某一对象的一个方法,用另一个对象替换当前对象。

语法:targetFunction.apply(thisArg,[arg1,arg2])

参数:

  1. 第一个参数 thisArg 会作为目标函数 targetFunction 运行时的 this 值传递给目标函数

  2. 第二个参数是传递给目标函数的参数数组

返回值:apply 方法的返回值和 bind 方法就完全不同了,它会直接调用并执行目标函数。

# call

调用一个对象的一个方法,以另一个对象替换当前对象。

语法:targetFunction.call(thisArg,arg1,arg2,...)

参数:

  1. 第一个参数 thisArg 会作为目标函数 targetFunction 运行时的 this 值传递给目标函数

  2. 后面的参数列表 arg1,arg2,... 是传递给目标函数的参数

返回值:apply 方法的返回值和 bind 方法就完全不同了,它会直接调用并执行目标函数。

# bind

应用某一对象的一个方法,用另一个对象替换当前对象

语法:targetFunction.bind(thisArg,arg1,arg2,...)

参数:

  1. 第一个参数 thisArg 会作为目标函数 targetFunction 运行时的 this 值传递给目标函数

  2. 后面的参数列表 arg1,arg2,... 是传递给目标函数的参数

返回值:bind 方法的返回值是一个目标函数的一个拷贝,

this 指向:这个拷贝出来的函数运行时 this 指向的就是调用 bind 传递的 thisArg 参数

注意:连续多个 bind 之后 this 指向始终指向第一个

# call、apply 和 bind 的区别

  1. call 的 arg 传参需一个一个传,apply 则直接传一个数组。

  2. call 和 apply 直接执行函数,而 bind 需要再一次调用

# 箭头函数 this 指向

箭头函数:调用者指向谁,(this)则指向谁

箭头函数的 this 指向,是父级程序的 this 指向:

  1. 如果父级程序有 this 指向,指向向的就是父级程序的 this 指向

  2. 如果父级程序没有 this 指向(对象,数组是没有 this),指向的是 window

更新时间: 2/10/2022, 7:21:32 PM
js 原型及原型链
js 作用域

← js 原型及原型链 js 作用域→

最近更新
01
前端权限管理
02-24
02
vue2指令
02-24
03
vue2 hook
02-24
更多文章>
Theme by Vdoing | Copyright © 2019-2022 放肆青春
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式