首先我们在 JavaScript 中,理解全局作用域、局部作用域、作用域链以及执行上下文是非常重要的。这些概念帮助我们掌握变量的可访问性和相关的执行机制。
1. 全局作用域
-
定义:全局作用域指的是在代码的最外层定义的变量和函数,任何地方都可以访问这些变量和函数。
-
使用:在浏览器环境中,全局作用域的对象是
window。例如,在全局作用域中定义的变量可以通过window.variableName访问。 -
示例:
var globalVar = "I am global"; function globalFunction() { console.log(globalVar); // accessible everywhere } globalFunction(); // 输出: I am global
2. 局部作用域
-
定义:局部作用域是指在函数内部定义的变量和函数,只能在该函数内部访问。
-
作用:使用局部作用域来封装变量,避免命名冲突和全局变量的污染。
-
示例:
function localFunction() { var localVar = "I am local"; console.log(localVar); // 可以访问 } localFunction(); // 输出: I am local // console.log(localVar); // 报错: Uncaught ReferenceError: localVar is not defined
3. 作用域链
-
定义:作用域链是指在 JavaScript 中,访问变量时会首先查找当前作用域的变量,如果没有找到,则向上查找外部作用域,直到全局作用域为止。
-
机制:如果在某个作用域内找不到变量,JavaScript 引擎会依次向上查找,形成一个链式结构。
-
示例:
var outerVar = "I am outside"; function outerFunction() { var innerVar = "I am inside"; function innerFunction() { console.log(innerVar); // 访问内层作用域 console.log(outerVar); // 访问外层作用域 } innerFunction(); } outerFunction(); // 输出: // I am inside // I am outside
4. 执行上下文
-
定义:执行上下文是 JavaScript 中代码执行的环境。每当函数被调用时,会创建一个新的执行上下文。
-
类型:
- 全局执行上下文:当 JavaScript 引擎首次加载代码时会创建一个全局执行上下文。
- 函数执行上下文:每次调用函数时,都会创建一个新的函数执行上下文。
-
组成:
- 变量对象(Variable Object) :存储该上下文中的所有变量和函数声明。
- 作用域链:当前执行上下文中的作用域链,用于查找变量。
- this 值:指向当前执行上下文的
this绑定对象。
-
示例:
function exampleFunction() { var localVariable = "Hello!"; console.log(localVariable); } exampleFunction(); // 创建一个新的函数执行上下文
小结
- 全局作用域:在整个代码中都可访问的作用域。
- 局部作用域:函数内部定义的作用域,仅在该函数内部可访问。
- 作用域链:查找变量的机制,从当前作用域向上查找外层作用域。
- 执行上下文:代码执行时的环境,包含变量对象、作用域链和
this值。
5. 前端变量污染
理解:
- 变量污染是指全局作用域中的变量被意外修改或覆盖,导致程序行为不符合预期的现象。在前端中,尤其在使用 JavaScript 时,若多个脚本共用全局作用域,变量名重复可能会引发此问题。
解决问题:
- 使用模块化编程和 ES6 的模块系统可以有效避免变量污染。通过将变量封装在模块内部,只有通过显式的导出(
export)和导入(import)方式来使用,能够限制全局命名空间的使用,从而减少变量污染的风险。
6. 变量提升
理解:
- 变量提升是指在 JavaScript 中,变量声明(
var和函数声明)会被提升到其作用域的顶部。无论变量声明的位置在哪里,整个作用域都会将变量提升到顶部。这意味着在使用变量之前,可以在代码中先声明它。
示例:
console.log(x); // undefined (没有报错)
var x = 5;
console.log(x); // 5
解决问题:
- 了解变量提升有助于开发者理解变量的作用域,提高代码的可读性。使用
let和const不会被提升,可以声明变量的位置提前避免在代码未执行前访问变量的问题。
7. 函数提升
理解:
- 函数提升是指函数声明会被提升到其作用域的顶部,允许在函数定义之前调用该函数。
示例:
myFunction(); // 输出 'Hello'
function myFunction() {
console.log('Hello');
}
解决问题:
- 函数提升确保了函数可以在定义之前被调用,这使得代码组织更加灵活,但也需要注意函数表达式(使用
var或let定义的函数)不会被提升。
8. let、const 和 var 的区别
-
var:- 权限:函数作用域。
- 提升:变量提升(可以在声明之前访问,但值为
undefined)。 - 解决问题:可以在函数内部声明变量,但在全局作用域中会造成命名冲突和变量污染。
-
let:- 权限:块作用域(如
{})。 - 提升:变量提升,但不初始化(在声明之前访问将抛出
ReferenceError)。 - 解决问题:减少全局变量,避免变量冲突,提供更强的作用域控制。
- 权限:块作用域(如
-
const:- 权限:块作用域。
- 提升:与
let类似(也不初始化)。 - 特点:声明常量,声明后不能被重新赋值。
- 解决问题:提供了更清晰的语义,指示开发者该变量应该保持不变。
小结
在现代 JavaScript 开发中,推荐优先使用 let 和 const 而非 var,以获得更好的作用域控制和代码可读性。
特别的 JavaScript 的严格环境
在 JavaScript 中,严格模式(Strict Mode)是一种限制 JavaScript 语法和行为的特性。使用严格模式可以帮助开发者编写健壮和安全的代码。严格模式可以使 JavaScript 代码在执行时表现得更加严格,从而防止常见的编码错误和不安全的行为。
如何启用严格模式
严格模式可以通过在脚本或函数的开始处添加 'use strict'; 字符串来启用。可以在全局作用域或在特定函数中使用。
1. 全局启用严格模式
'use strict';
function myFunction() {
// 在这里都是严格模式
let x = 3.14;
}
2. 函数级启用严格模式
function myFunction() {
'use strict';
// 只有在这个函数内部是严格模式
let y = 3.14;
}
严格模式的特点和好处
-
禁止使用未声明的变量:
- 在严格模式中,如果尝试使用未声明的变量,会抛出错误。
'use strict'; x = 20; // ReferenceError: x is not defined -
禁止删除变量、函数或参数:
- 在严格模式中,不能使用
delete操作符删除变量、函数或参数。
'use strict'; var x = 10; delete x; // SyntaxError: Delete of an unqualified identifier in strict mode. - 在严格模式中,不能使用
-
禁止重复参数名:
- 函数的参数不能有相同的名称。
'use strict'; function sum(a, a, c) { // SyntaxError: Duplicate parameter name not allowed in this context return a + a + c; } -
禁止使用
this关键字指向全局对象:- 在严格模式下,函数的
this关键字不再指向全局对象window,而是undefined(在调用时没有明确绑定)。
'use strict'; function f() { console.log(this); // undefined } f(); - 在严格模式下,函数的
-
给
this赋值为undefined:- 在严格模式下,
this的值如果没有被绑定将是undefined,而不是全局对象。
- 在严格模式下,
-
限制某些语法:
- 严格模式下禁止使用某些不推荐使用的特性,如
with语句。
'use strict'; with (Math) { // SyntaxError: Strict mode code may not include a with statement x = cos(2); } - 严格模式下禁止使用某些不推荐使用的特性,如
-
改进的错误处理:
- 严格模式可以使错误更显式。试图使用一些不安全的行为会引发错误,帮助开发者更快地发现问题。
适用范围
- 全局范围:通过在文件的第一行添加
'use strict';,整个文件都处于严格模式。 - 函数范围:通过在函数内部添加
'use strict';,只有该函数内部有效。
小结
JavaScript 的严格模式是一种提高代码安全性和可维护性的机制。通过限制某些行为和语法,严格模式帮助开发者更快地发现潜在错误,写出更健壮的代码。推荐在编写 JavaScript 代码时使用严格模式,尤其是在较大的项目中,能有效减少错误和提升开发质量。
this的理解
this关键字是一个非常重要但也容易引起混淆的概念。this的值取决于函数调用的方式,并且在不同的上下文中可能有不同的含义。下面是一些关键点来帮助深刻理解this**:**
-
全局作用域中的
this:- 在浏览器环境中,如果代码不是在严格模式下运行,全局作用域中的
this指向window对象。 - 如果是在严格模式(
'use strict';)下,全局作用域中的this为undefined。
- 在浏览器环境中,如果代码不是在严格模式下运行,全局作用域中的
-
函数调用模式:
- 当一个函数作为普通函数被调用时(即没有被绑定到任何对象上),
this通常指向全局对象(非严格模式)或undefined(严格模式)。
- 当一个函数作为普通函数被调用时(即没有被绑定到任何对象上),
-
方法调用模式:
- 当函数作为某个对象的方法被调用时,
this会绑定到这个对象。 - 例如,在对象的方法中,
this通常指的是该对象本身。
- 当函数作为某个对象的方法被调用时,
-
构造函数模式:
- 使用
new关键字调用函数时,this绑定到新创建的对象实例。 - 这种情况下,
this指向新创建的对象,并且该对象将成为函数执行结果的对象。
- 使用
-
箭头函数中的
this:- 箭头函数不绑定自己的
this值;它们继承自外层(通常是父级)作用域的this值。 - 这意味着箭头函数内部的
this值取决于定义时所在的上下文,而不是调用时的上下文。
- 箭头函数不绑定自己的
-
显式绑定
this:- 可以使用
.bind()、.call()或.apply()方法来显式地设置函数执行时的this值。 - 这些方法允许开发者明确指定
this应该指向哪个对象。
- 可以使用
理解this的关键在于记住它的值是由函数调用的方式决定的,而不是函数定义的位置。这对于编写可重用和灵活的代码至关重要。在实际开发中,特别是在处理事件处理器、回调函数或者类的方法时,正确理解和管理this是非常重要的。
大总结
JavaScript 是一种灵活、强大的编程语言,说简单也不简单,js里面太多概念需要深刻去理解和关联/串联起来思考了。比如如下 JavaScript 使用严格模式带来的好处:
-
消除不安全的引用:
- 在严格模式下,试图引用未声明的变量会导致一个
ReferenceError错误。 - 严格模式禁止对全局对象的属性进行无意的赋值。
- 在严格模式下,试图引用未声明的变量会导致一个
-
限制变量声明:
- 在严格模式下,不允许重复声明同一个变量或函数。
- 不能在函数内部使用
eval或者间接引用 (arguments.callee和arguments.caller)。
-
提升代码安全性:
- 禁止使用
with语句,这有助于避免潜在的命名冲突问题。 - 对象不可配置的属性不能被删除(除非该属性是可配置的)。
- 禁止使用
-
改进调试体验:
- 严格模式会强制执行更严格的解析规则,比如不允许八进制字面量。
- 在严格模式下,未使用的参数将引发警告。
-
性能优化:
- 在某些情况下,启用严格模式可以使 JavaScript 引擎更好地优化代码执行。
- 减少了不必要的操作,提高了代码的执行效率。
-
其他限制:
- 严格模式还限制了某些特殊的、容易出错的操作,如对未定义变量的赋值。
上面谈及的概念也做个总结
全局作用域(Global Scope)
- 定义:全局作用域是 JavaScript 运行时的最外层作用域,在全局作用域中声明的变量和函数可以被整个代码所访问。
- 特性:在浏览器中,全局作用域的对象是
window,全局变量可以通过window.variableName访问。 - 注意:过多的全局变量可能会导致命名冲突和变量污染。
局部作用域(Local Scope)
- 定义:局部作用域是指在函数内部或代码块(
{})中定义的作用域,只能在该函数或代码块内部访问。 - 特性:局部作用域能够有效管理变量,避免变量污染。
3. 作用域链(Scope Chain)
- 定义:作用域链是 JavaScript 查找变量时的机制。当访问变量时,JavaScript 首先查找当前作用域的变量,如果找不到,就逐层向上查找外层作用域,直到全局作用域。
- 特性:这种机制确保了可以在嵌套函数中访问外层函数的变量。
4. 执行上下文(Execution Context)
-
定义:执行上下文是代码执行时的环境,它可以理解为来自不同执行环境的状态信息的集合。
-
类型:
- 全局执行上下文:代码首次执行时创建的上下文。
- 函数执行上下文:每次调用函数时创建的新的上下文。
-
组成:包括变量对象(存储所有变量和函数声明)、作用域链和
this绑定。
5. 变量污染(Variable Pollution)
- 定义:变量污染是指全局作用域中的变量被意外修改或覆盖,通常是因为全局变量和局部变量命名冲突导致的。
- 影响:可能引发逻辑错误和不可预测的行为。
- 解决方案:使用局部作用域、模块化开发和 ES6 的模块导入导出来避免。
6. 变量提升(Variable Hoisting)
- 定义:变量提升是指变量声明会被提升到其作用域的顶部。在访问变量之前,你可以在代码中先声明它。
- 特性:只有声明会被提升,赋值不会提升。
7. 函数提升(Function Hoisting)
- 定义:函数声明会被提升到其作用域的顶部,可以在定义之前调用。
- 区别:函数表达式(例如,通过
var定义的函数)不会被提升。
8. let、const 和 var 的区别
-
var:- 权限:函数作用域。
- 提升:变量提升(未初始化时为
undefined)。 - 特性:不支持块作用域,容易导致变量污染。
-
let:- 权限:块作用域(如
{})。 - 提升:变量提升,但不初始化(访问会报错)。
- 特性:防止变量重复报名,减少全局变量的使用。
- 权限:块作用域(如
-
const:- 权限:块作用域。
- 提升:与
let相同。 - 特性:声明常量,确保在后续代码中该变量无法被重新赋值。
完结。每次学习一遍基础概念基础知识总结一下就感觉有不一样的理解,红宝石书也是写的很多细节概念没有去深入过对比过,这次一并总结几个常用常问的概念~卷王不是终点,不断学习才是终点!!!