应用 let 和 const 申明变量早曾经司空见惯了。笔者作为面试官面试过上百人,能精确了解 let/const 块级作用域以及的候选人有余一二。本文将深入研究 let 和 const 的实现原理,以及多种形式来模仿公有变量,心愿本文能给初中级前端小伙伴们一点帮忙。
一、let
和 const
的实现原理
1.1 JavaScript 的作用域链
在深刻理解 let
和 const
前,让咱们首先回顾一下 JavaScript 中的作用域。作用域是一个决定变量可见性和拜访性的概念。JavaScript 具备两种次要的作用域:全局作用域和函数作用域。
全局作用域是整个程序的顶层作用域,其中申明的变量能够在程序的任何中央拜访。函数作用域限定了变量的作用范畴,只有在函数外部能力拜访这些变量。
1.2 词法环境和变量对象
JavaScript 引擎应用词法环境来治理变量和函数的作用域。词法环境包含两个重要局部:词法环境记录和对外部词法环境的援用。
词法环境记录是一个外部数据结构,用于存储变量和函数申明。全局环境的词法环境记录蕴含全局变量和函数,而函数环境的词法环境记录蕴含局部变量和参数。
1.3 let
和 const
的块级作用域
ES6 引入了 let
和 const
,它们引入了块级作用域的概念。块级作用域容许咱们在 {}
外部创立独立的作用域,使得变量仅在该块内无效。
if (true) {
let x = 10;
const y = 20;
}
console.log(x); // 报错:x is not defined
console.log(y); // 报错:y is not defined
在下面例子中,x
和 y
只在 if
语句块内可见,内部无法访问它们。
1.4 let
和 const
的长期死区
let
和 const
引入了“长期死区”(Temporal Dead Zone,TDZ)的概念。TDZ 是指在变量申明之前,变量无奈被拜访或赋值的状态。
console.log(x); // 报错:Cannot access 'x' before initialization
let x = 10;
在下面例子中,因为 x
在申明之前被拜访,触发了 TDZ,导致报错。
1.5 const
的不可变性
const
申明的变量是不可变的,一旦赋值后不能再从新赋值。但须要留神的是,对于援用类型的变量,尽管变量自身不可从新赋值,但其属性依然能够批改。
const pi = 3.14159;
pi = 3.14; // 报错:Assignment to constant variable.
const person = {name: 'John'};
person.name = 'Alice'; // 可行
在下面例子中,pi
因为是根本数据类型,不能被从新赋值。而 person
是一个对象,尽管不能从新赋值 person
,但能够批改其属性。
二、模仿公有变量
2.1 闭包的基本原理
闭包是 js 中的一个概念,它容许函数拜访其内部作用域的变量,即便内部作用域曾经执行结束。闭包通过将外部函数援用到内部函数的变量来实现。
function createCounter() {
let count = 0;
// 外部函数 increment 闭包了内部函数 createCounter 的变量 count
function increment() {
count++;
console.log(count);
}
return increment;
}
const counter = createCounter();
counter(); // 输入 1
counter(); // 输入 2
在下面例子中,createCounter
函数返回了一个外部函数 increment
,该外部函数可能拜访并批改内部函数的 count
变量。这就是闭包的基本原理。
2.2 应用函数闭包
通过函数闭包,咱们能够封装变量并模仿实现公有变量的行为。咱们能够创立一个函数,该函数蕴含了须要爱护的变量,并返回用于拜访和批改这些变量的办法。
function createPrivateVariable(initialValue) {
let value = initialValue;
return {getValue: function () {return value;},
setValue: function (newValue) {value = newValue;},
};
}
const privateVar = createPrivateVariable(42);
console.log(privateVar.getValue()); // 输入 42
privateVar.setValue(100);
console.log(privateVar.getValue()); // 输入 100
在下面例子中,createPrivateVariable
函数返回了一个对象,该对象蕴含了两个办法 getValue
和 setValue
,用于拜访和批改公有变量 value
。这样,咱们胜利地模拟出了一个公有变量的成果,内部无奈间接拜访或批改它。
2.3 模块模式
模块模式是一种常见的实现公有变量的形式,特地实用于大型应用程序的模块化设计。模块模式利用了函数作用域和闭包的个性,将公有变量和办法封装在一个函数外部,并返回一个蕴含私有办法的对象。
const myModule = (function () {
// 公有变量
let privateVar = 0;
// 公有办法
function privateFunction() {
// 能够拜访 privateVar
privateVar++;
}
// 私有办法
return {increment: function () {privateFunction();
},
getValue: function () {return privateVar;},
};
})();
myModule.increment();
console.log(myModule.getValue()); // 输入 1
在下面例子中,myModule
是一个立刻执行函数,它创立了一个闭包,蕴含了公有变量 privateVar
和公有办法 privateFunction
。而后,通过返回一个蕴含私有办法的对象,咱们能够拜访和操作公有变量,同时将其封装起来,不会受到内部的烦扰。
2.4 ES6 中的 Symbol
ES6 引入了 Symbol 数据类型,它能够用于创立惟一的属性键,从而实现公有属性。每个 Symbol 值都是惟一的,不会与其余属性键抵触。
const privateVariable = Symbol('privateVar');
const obj = {[privateVariable]: 42,
};
console.log(obj[privateVariable]); // 输入 42
在这个示例中,咱们应用 Symbol 创立了一个公有属性键 privateVariable
,而后将其作为对象的属性。这个公有属性对外部是不可见的,只能通过应用雷同的 Symbol 能力拜访。
三、总结
深刻了解 js 的 let
和 const
变量申明以及模仿实现公有变量的办法,咱们能够更好地把握 JavaScript 的外围概念。
本文咱们探讨了 js 的作用域、块级作用域、闭包、let
和 const
的行为,以及模仿公有变量的多种形式, 心愿可能帮忙读者更好的了解 js 的外围概念。如果本文对你有帮忙,记得点赞关注我哦~