目录
执行上下文属性:变量对象、this,作用域链
变量对象是与执行上下文相关的数据作用域,存储:变量、函数声明
执行上下文生命周期
创建:生成变量对象、创建函数作用域,建立作用域链、确定this的指向
执行:变量赋值、函数的引用(调用时用指针)、执行其他代码
全局执行上下文:this 指向window全局对象
函数执行上下文:每次调用会创建新的执行上下文
()=>{}应用:共享外部函数的执行上下文(this、性能优化)
作用域:可访问变量的集合
全局作用域
函数作用域:在函数定义的时候就决定了
块级作用域(ES6):{}
作用链=作用域链表
查找不到:原型链undefined,作用域链ReferenceError
this:谁调用就指向谁,除非绑定
全局环境(普通函数/匿名函数):window/undefined 严格模式
JS
非严格模式:对象
严格模式:任意值
改变this中的thisArg
new 运算符构造绑定函数:提供的 this 值会被忽略(因为构造函数会准备自己的 this
new.target
原始值转换为对象:->Number/String
全局对象替换:null/undefined->window(非严格模式)
bind
HTML
React的class实例
执行上下文属性:变量对象、this,作用域链
const ExecutionContextObj = {VO: window, // 变量对象ScopeChain: {}, // 作用域链this: window
};
变量对象是与执行上下文相关的数据作用域,存储:变量、函数声明
生成变量对象:
- 创建arguments
- 扫描函数声明
- 扫描变量声明
执行上下文生命周期
创建:生成变量对象、创建函数作用域,建立作用域链、确定this的指向
执行:变量赋值、函数的引用(调用时用指针)、执行其他代码
全局执行上下文:this 指向window全局对象
函数执行上下文:每次调用会创建新的执行上下文
()=>{}应用:共享外部函数的执行上下文(this、性能优化)
//函数内部找不到就会去外层作用域
function foo() {console.log(a);
}function bar() {let a="bar"foo();
}
let a="window"
bar(); //window
浏览器调试工具
作用域:可访问变量的集合
作用域最大的用处就是隔离变量
,不同作用域下同名变量不会有冲突
全局作用域
函数作用域:在
函数定义的时候就决定了
块级作用域(
ES6):{}
作用链=作用域链表
查找不到:原型链undefined,作用域链ReferenceError
this:谁调用就指向谁,除非绑定
全局环境(普通函数/匿名函数):window/undefined 严格模式
// 整个脚本都开启严格模式的语法
"use strict";
var v = "Hi! I'm a strict mode script!";
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
参数传入了 null
或 undefined
,在非严格模式下,它们会被替换为全局对象(通常是 window
对象)。这是为了确保函数始终有一个合法的 this
对象,防止出现错误。在严格模式下,null
或 undefined
不会被替换,函数内部的
"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
将保持为 null
或 undefined
。
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: undefinedconst 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 和 Componentclass APP extends Component {constructor(props) {super(props);// 将 handleClick 方法绑定到组件实例的上下文this.handleClick5 = this.handleClick5.bind(this);}handleClick1(ev) {console.log(this);//undefinedconsole.log(ev);//合成的SyntheticBaseEvent console.log(ev.target);//button}//箭头函数//方法A:类中箭头handleClick2 = () => {console.log(this);//APP类组件实例}//方法B:onclick中箭头handleClick3() {console.log(this);//APP类组件实例}// bind绑定组件实例this// 方法A:onclickhandleClick4() {console.log(this); //APP类组件实例}// 方法B:constructorhandleClick5() {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;