JavaScript原型、闭包与执行上下文核心机制解析
本文详细解析JavaScript核心概念,包括闭包作为函数局部变量集合的持久化机制,以及原型对象在属性继承中的作用。重点阐述执行上下文(EC)的创建过程,涵盖全局、函数及Eval代码段的“准备工作”,如变量声明提升、this赋值及自由变量作用域的确定,帮助开发者深入理解JS内存管理与作用域规则。
相关系列文章:《谈谈我对JavaScript原型和闭包系列理解(随手笔记8)》与《谈谈我对JavaScript原型和闭包系列理解(随手笔记9)》。
闭包机制解析
什么是闭包
闭包(Closure)是静态语言中不具备的特性,但并非难以理解。简而言之,闭包的定义如下:
• 闭包是函数的局部变量集合,这些局部变量在函数返回后依然保持存在。
• 闭包意味着函数返回后,其“堆栈”不会释放;也可以理解为这些函数堆栈并非分配在栈上,而是分配在堆上。
• 当在一个函数内部定义另一个函数时,就会产生闭包。
原型与继承
什么是原型?
原型是一个对象,其他对象可以通过它实现属性继承。
是否任何对象都可以成为原型?
是。
哪些对象拥有原型?
所有对象默认情况下都拥有一个原型。由于原型本身也是对象,因此每个原型自身又有一个原型(唯一的例外是位于原型链顶端的那个默认对象原型)。
执行上下文与变量提升
执行上下文
每当控制器转向执行ECMAScript可执行代码时,就会进入一个执行上下文。
执行上下文(简称EC)是一个抽象概念,ECMA-262标准利用该概念来区分可执行代码(executable code)。
标准规范并未从技术实现角度精确定义EC的类型和结构,这属于具体ECMAScript引擎实现时需考虑的问题。
活动的执行上下文在逻辑上组成一个堆栈。堆栈底部始终是全球上下文(global context),堆栈顶部是当前(活动的)执行上下文。当EC类型的变量被推入或弹出时,堆栈随之修改。
--------------------------------------------------------------------------------
情况一:在一段JS代码真正逐句运行之前,浏览器已执行部分“准备工作”,其中包括变量声明而非赋值。变量赋值发生在赋值语句执行时。
情况二:在“准备工作”阶段,this是直接赋值的。
代码如下:
console.log(this) //Window情况三:函数:函数表达式和函数声明。
console.log(f1); //function f1() {}
function f1() {} //函数声明
console.log(f2); //undefined
var f2 = function() {}; //函数表达式
“准备工作”总结:
• 变量、函数表达式————变量声明,默认赋值为undefined
• this————赋值
• 函数声明————赋值
这三种数据的准备情况我们称之为“执行上下文”或者“执行上下文环境”。
--------------------------------------------------------------------------------
JavaScript在执行一个代码段之前,都会进行这些“准备工作”来生成执行上下文。这个“代码段”分为三种情况--全局代码、函数代码、Eval代码。
//全局代码段
<script type="text/javascript">
//代码段...
</script>
//函数代码段
function fn(x) {
console.log(x + 5);
}
var fn = new Function("x", "console.log(x + 5)");
//Eval代码段
eval('var x = 10');
(function foo() {
eval('var y = 20');
})();
alert(x); //10
alert(y); //"y" is not defined
//因为eval涉及到安全问题(脚本注入),所以尽量不用。
--------------------------------------------------------------------------------
在函数中,除了“准备工作”的几种情况,还会有其他数据
function fn(x) {
console.log(arguments); //[10]
conosole.log(x); //10
}
fn(10);
以上代码展示了在函数体的语句执行之前,arguments变量和函数参数都已经被赋值。
函数每被调用一次,都会产生一个新的上下文执行环境。因为不同调用那个就可能产生不同的参数。
函数在定义的时候(不是调用)就已经确定了函数体内部自由变量的作用域。
var a = 10;
function fn() {
console.log(a); //a是自由变量
} //函数创建时,就确定了a要取值的作用域
function bar(f) {
var a = 20;
f(); //打印"10",而不是"20"
}
bar(fn);
总结:
全局代码的上下文环境数据内容为:
• 普通变量(包括函数表达式),如:var a = 10 | ===> 声明(默认赋值undefined)
• 函数声明,如function fn() {} | ===> 赋值
• this | ===> 赋值
函数体
• 参数 | ===> 赋值
• arguments | ===> 赋值
• 自由变量的取值作用域 | ====> 赋值
通俗的定义:
在执行代码之前,把将要用到的所有变量都事先拿出来,有的直接赋值了,有的先用undefined占个位。
以上内容是小编给大家分享的JavaScript原型和闭包系列理解(随手笔记6)的全部叙述,希望大家喜欢。
ES6模块化中js文件怎么用import和export交互
2026-11-05 17:00:48
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
