JS、React、HTML的执行上下文this,this\that\self,作用域

52 篇文章 14 订阅
10 篇文章 0 订阅

目录

执行上下文:管理和执行代码

属性:变量对象、this,作用域链

变量对象是与执行上下文相关的数据作用域,存储:变量、函数声明

生命周期

创建:生成变量对象、创建函数作用域,建立作用域链、确定this的指向

执行:变量赋值、函数的引用(调用时用指针)、执行其他代码

分类:按执行时机

全局执行上下文:this 指向window全局对象

函数执行上下文:每次调用会创建新的执行上下文

应用:()=>{}共享外部函数的执行上下文(this、性能优化)

eval 执行上下文:动态创建的代码

不推荐原因:XSS攻击、动态编译、维护性

作用域:可访问变量的集合

全局作用域

函数作用域:在函数定义的时候就决定了

块级作用域(ES6):{}

作用链=作用域链表

查找不到:原型链undefined,作用域链ReferenceError

this:哪个对象调用就指向哪个,除非绑定(call、apply、bind)

直接访问时(不作为对象的调用):调用对象与定义位置无关

省略this时:指向window/undefined 严格模式

this\that\self:引用组件实例的关键字

that\self:闭包或回调函数中保持对组件的引用

JS

非严格模式:对象

严格模式:任意值

改变this中的thisArg

new 运算符构造绑定函数:提供的 this 值会被忽略(因为构造函数会准备自己的 this

new.target

原始值转换为对象:->Number/String

全局对象替换:null/undefined->window(非严格模式)

bind

HTML

React的class实例

vue2:this=组件实例($router,$ref)

vue3:{ proxy, appContext } = getCurrentInstance()


执行上下文:管理和执行代码

属性:变量对象、this,作用域链

const ExecutionContextObj = {
    VO: window, // 变量对象
    ScopeChain: {}, // 作用域链
    this: window
};

变量对象是与执行上下文相关的数据作用域,存储:变量、函数声明

生成变量对象:

  • 创建arguments
  • 扫描函数声明
  • 扫描变量声明

生命周期

创建:生成变量对象、创建函数作用域,建立作用域链、确定this的指向

执行:变量赋值、函数的引用(调用时用指针)、执行其他代码

分类:按执行时机

全局执行上下文:this 指向window全局对象

函数执行上下文:每次调用会创建的执行上下文

应用:()=>{}共享外部函数的执行上下文(this、性能优化)

eval 执行上下文:动态创建的代码

不推荐原因:XSS攻击、动态编译、维护性

//函数内部找不到就会去外层作用域
function foo() {
  console.log(a);
}

function bar() {
  let a="bar"
  foo(); 
}
let a="window"
bar(); //window

浏览器调试工具

作用域:可访问变量的集合

作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突

全局作用域

函数作用域:在函数定义的时候就决定了

块级作用域(ES6):{}

作用链=作用域链表

查找不到:原型链undefined,作用域链ReferenceError

this:哪个对象调用就指向哪个,除非绑定(callapplybind

直接访问时(不作为对象的调用):调用对象与定义位置无关

var a=1;
function fn1(){
  var a=2;
  console.log(this.a+a);
}
//f1并没有被作为对象的方法调用, this 指向全局对象,在浏览器中是 window
fn1();//3 

function fn2(){
  var a=10;
  fn1();
}
//调用对象与定义位置无关
fn2();//3 

省略this时:指向window/undefined 严格模式

// 整个脚本都开启严格模式的语法
"use strict";
var v = "Hi!  I'm a strict mode script!";

this\that\self:引用组件实例的关键字

that\self:闭包或回调函数中保持对组件的引用

ES5及之前,由于函数作用域的问题,this 可能不会指向预期的上下文,

因此在函数外部定义一个 thatself 变量指向 this

export default {
  data() {
    return {
      name: 'Vue'
    };
  },
  created() {
    var self = this; // 或者 var that = this;
    setTimeout(function() {
      console.log(`Hello, ${self.name}!`); // 在这里使用 self 代替 this
    }, 1000);
  }
}

JS

当前执行上下文(global、function 或 eval)的一个属性:this

可以使用 globalThis 获取全局对象,无论你的代码是否在当前上下文运行。

非严格模式对象

严格模式任意值

如果进入执行环境时没有设置 this 的值,this 会保持为 undefined

function f2() {
  "use strict"; // 这里是严格模式
  return this;
}

f2() === undefined; // true

改变this中的thisArg

new 运算符构造绑定函数:提供的 this 值会被忽略(因为构造函数会准备自己的 this

new.target
//如果构造函数是通过 new 运算符来调用的,则 new.target 将指向构造函数本身,否则它将是 undefined
//new.target 是一个在构造函数中可用的元属性(meta-property),用于检查构造函数是如何被调用的。而 Base 是一个类(或构造函数)的名称
class Base {
  constructor(...args) {
    console.log(new.target === Base);
    console.log(args);
  }
}

const BoundBase = Base.bind(null, 1, 2);

new BoundBase(3, 4); // true, [1, 2, 3, 4]
function Greet(name) {
  this.name = name;
}

const person = {
  name: "Alice"
};

// 使用 bind 创建绑定函数,将 this 设置为 person
const boundGreet = Greet.bind(person, "Bob");

// 使用 new 运算符尝试构造绑定函数
const newGreet = new boundGreet();

console.log(newGreet.name); // 输出 "Bob",而不是 "Alice"

原始值转换为对象:->Number/String

期望 this 是一个对象,但 thisArg 参数是一个原始值(比如数字、字符串等),则 thisArg 会被转换为对应的包装对象。例如,如果 thisArg 是一个数字,它将被转换为 Number 包装对象

严格模式下,不允许将原始值(如字符串、数字、布尔值)包装为对应的对象(String、Number、Boolean),而是保持它们的原始类型

"use strict"; // 防止 `this` 被封装到到包装对象中

function log(...args) {
  console.log(this, ...args);
}
const boundLog = log.bind("this value", 1, 2);
const boundLog2 = boundLog.bind("new this value", 3, 4);
boundLog2(5, 6); // "this value", 1, 2, 3, 4, 5, 6
//不用严格模式,则输出{"this value"}, 1, 2, 3, 4, 5, 6

全局对象替换:null/undefined->window(非严格模式)

如果 thisArg 参数传入了 nullundefined,在非严格模式下,它们会被替换为全局对象(通常是 window 对象)。这是为了确保函数始终有一个合法的 this 对象,防止出现错误。在严格模式下,nullundefined 不会被替换,函数内部的

"use strict"; // 防止 `this` 被封装到到包装对象中

function log(...args) {
  console.log(this, ...args);
}
const boundLog = log.bind("this value", 1, 2);
const boundLog2 = boundLog.bind("new this value", 3, 4);
boundLog2(5, 6); // "this value", 1, 2, 3, 4, 5, 6

this 将保持为 nullundefined

bind

const module = {
  x: 42,
  getX: function () {
    return this.x;
  },
};

const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// Expected output: undefined

const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// Expected output: 42

绑定函数将绑定时传入的参数(包括 this 的值和前几个参数)提前存储为其内部状态。而不是在实际调用时传入。

通常情况下,你可以将 const boundFn = fn.bind(thisArg, arg1, arg2) 和 const boundFn = (...restArgs) => fn.call(thisArg, arg1, arg2, ...restArgs) 构建的绑定函数的调用效果视为等效

绑定函数可以通过调用 boundFn.bind(thisArg, /* more args */) 进一步进行绑定,从而创建另一个绑定函数 boundFn2。新绑定的 thisArg 值会被忽略,因为 boundFn2 的目标函数是 boundFn,而 boundFn 已经有一个绑定的 this 值了。

HTML

<button onclick="click(this)">传进去的为当前button</button>
<button onclick="click()">click()中直接使用this为window</button>

React的class实例

  

import React, { Component } from 'react'; // 请确保导入 React 和 Component

class APP extends Component {
  constructor(props) {
    super(props);
    // 将 handleClick 方法绑定到组件实例的上下文
    this.handleClick5 = this.handleClick5.bind(this);
  }
  handleClick1(ev) {
    console.log(this);//undefined
    console.log(ev);//合成的SyntheticBaseEvent 
    console.log(ev.target);//button
  }
  //箭头函数
  //方法A:类中箭头
  handleClick2 = () => {
    console.log(this);//APP类组件实例
  }
  //方法B:onclick中箭头
  handleClick3() {
    console.log(this);//APP类组件实例
  }
  // bind绑定组件实例this
  // 方法A:onclick
  handleClick4() {
    console.log(this);   //APP类组件实例
  }
  // 方法B:constructor
  handleClick5() {
    console.log(this); //APP类组件实例  
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick1}>点击1</button>
        {/* 箭头函数 */}
        <button onClick={this.handleClick2}>点击2</button>
        <button onClick={() => { this.handleClick3() }}>点击3</button>
        {/* bind */}
        <button onClick={this.handleClick4.bind(this)}>点击4</button>
        <button onClick={this.handleClick5}>点击5</button>
      </div>
    );
  }
}

export default APP;

vue2:this=组件实例($router,$ref)

vue3:{ proxy, appContext } = getCurrentInstance()

<script setup>
import { getCurrentInstance } from 'vue'

// proxy 就是当前组件实例,可以理解为组件级别的 this,没有全局的、路由、状态管理之类的
const { proxy, appContext } = getCurrentInstance()

// 这个 global 就是全局实例
const global = appContext.config.globalProperties
</script>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值