IT技术博客大学习 共学习 共进步

标签:Scope

共 11 篇相关文章

IT 累计浏览 4,340

JavaScript的闭包问题

这篇讲的是 JavaScript 闭包在循环中一个经典的陷阱。作者从一个看似简单的需求出发:在一个 `for` 循环中创建三个函数,分别打印当前的循环索引。但实际执行时,所有函数都打印了同一个值——循环结束后的最终值。 问题的根源在于闭包捕获的是变量的引用,而非创建时的快照。循环变量 `i` 在所有函数中都是同一个变量,因此函数执行时读取的都是循环结束后那个值。即使尝试在循环内用 `var n = i` 复制一份,由于 JavaScript 缺乏块级作用域,`n` 的作用域依然是整个外层函数,最终也会被后续的迭代覆盖。 作者指出,这条“不要在闭包中直接引用循环变量”的原则,适用于所有函数式语言。正确的做法是创建一个新的作用域来捕获当前迭代的值。文章演示了两种经典方案:一是通过一个额外的函数(如 `function(n){...}`)将当前 `i` 作为参数传入;二是更简洁的立即执行函数表达式(IIFE),在循环体内 `(function(n){...})(i)` 就地创建一个新作用域并传递参数。 这本质上是一个作用域与闭包机制如何相互作用的深度理解问题。掌握这个模式,能帮开发者避免在异步回调、事件监听等场景下产生难以排查的 bug。

IT 累计浏览 4,561

揭秘JavaScript中谜一样的this

这篇讲的是JavaScript中this关键字的工作原理,作者从开发者常见的困惑入手,揭示了this在不同调用场景下的行为差异。文章首先对比了函数作为对象方法调用和获取引用后调用的区别:直接调用时this指向对象本身,但提取方法后调用可能让this指向全局window,在严格模式下则变为undefined。接着,探讨了this在构造函数中的角色,使用new关键字时this指向新实例,否则可能意外指向全局对象。 文章进一步介绍了如何通过.call、.apply和.bind来主动操作this,提供了灵活的解决方案。.call允许传递任意参数并指定this,.apply则接受数组参数,.bind能永久绑定this并创建部分参数的函数。这些工具帮助开发者应对this的“脆弱”特性,避免常见陷阱。 在作用域链部分,文章指出this无法自动继承的问题,建议使用局部变量如var self = this或.bind来保留引用,确保在嵌套函数中正确使用。通过具体代码示例,文章澄清了this的复杂机制,让读者能更清晰地理解其在JavaScript中的角色,提升代码编写能力。

IT 累计浏览 3,420

认识javascript中的作用域和上下文

这篇讲的是JavaScript中作用域和上下文这两个常被混淆却至关重要的核心概念。作者首先澄清,作用域是函数调用时变量的可访问范围,每次调用独立;而上下文主要指this关键字的值,取决于函数的调用方式。 文章深入剖析了两者的差异与关联:局部与全局变量的作用域区别,并指出ES6的let带来了块级作用域;this在不同调用场景(对象方法、new创建实例、默认调用、严格模式)下的不同绑定结果。作者还详解了执行上下文与作用域链的机制,说明变量查找如何沿链上溯。 在此基础上,文章展示了这些概念如何支撑JavaScript的高级模式。闭包通过维持对外部函数作用域的引用实现数据封装,并衍生出模块模式和IIFE(立即调用函数表达式)来保护全局命名空间。而call、apply和bind方法则提供了动态控制函数执行上下文的能力,在面向对象编程和事件处理中解决上下文丢失问题。 对于想深入理解JavaScript语言机制和设计模式的开发者而言,厘清作用域与上下文是绕不开的关键一步。

IT 累计浏览 1,701

Javascript中的delete操作符

这篇文章深入剖析了JavaScript中`delete`操作符的行为,特别是它与变量、对象属性之间微妙而关键的互动关系。作者从一个核心矛盾出发:看似等价的全局变量和对象属性,在`delete`面前却表现迥异。 核心差异在于,通过`var`声明的变量和函数声明都带有`dontdelete`特性,因此它们无法被`delete`操作符移除。相比之下,直接在对象上创建的属性(无论是自定义的还是来自原型链的)则可以被轻松删除。文章通过一系列精准的代码示例展示了这种区别,例如`delete global`对`var global`无效,但`delete obj`却能移除一个未用`var`声明的全局变量(它本质上是`window`对象的属性)。 此外,文章还细致地探讨了`delete`操作符的几个边界情况:它无法删除原型(prototype)中定义的属性或对象自带的属性(如`length`);在`eval`执行的代码中,通过`var`声明的变量反而失去了`dontdelete`保护,可以被删除;而`delete`的返回值(`true`/`false`)更多反映了操作是否成功,而非属性是否真的存在。理解这些细节,对于避免JavaScript中关于删除操作的常见陷阱至关重要。

IT 累计浏览 4,700

C语言全局变量那些事儿

这篇讲的是C语言全局变量多重定义的“危险”与“微妙”行为。作者从全局变量在不同视角(程序员、编译器、计算机)下的不同含义切入,通过三个递进的代码示例,深入剖析了编译链接器对“强符号”与“弱符号”的解析规则。 文章揭示了一个常被忽略的隐患:C语言实际上“允许”全局变量的多重定义(只要不是多个强符号),这可能导致内存被意外覆盖。示例中,同一个变量名在不同文件里可以是结构体或整型,却链接到同一块内存,其初始化值会发生覆盖。作者进一步展示了在多进程(fork)环境下,这种行为如何与操作系统的“写时拷贝”机制相互作用,使得不同进程的同一虚拟地址映射到不同的物理内存,从而产生隐蔽的状态差异。 最后,通过将代码编译为静态库链接,作者验证了这种行为在静态链接下依然存在。这篇文章的价值在于,它用具体而震撼的运行结果,将抽象的链接原理和潜在风险可视化,提醒开发者谨慎对待全局变量,尤其是非static限定的全局变量。

IT 累计浏览 3,421

Javascript中的delete操作符

这篇从JavaScript中一个看似简单的delete操作符切入,但探讨的问题却非常根本:变量和对象属性之间的微妙关系。作者首先指明,要理解delete的行为,必须先理清JavaScript执行引擎在幕后创建的Global对象(浏览器中即window对象)和Activation对象(函数执行上下文)。所有全局和局部变量,本质上都是这些对象的属性。 文章通过一个代码示例生动地说明了这一点:在全局作用域中声明变量 `global` 后,可以通过 `this.global` 访问,这直接证明了变量作为Global对象属性的存在。基于这个核心视角,文章随后便能清晰剖析delete操作符的实质——它针对的是对象的属性,而非传统意义上的“变量声明”。这也解释了为什么delete无法删除通过var声明的变量或函数声明,因为它们被标记为不可配置。 作者从底层对象模型出发,把一个操作符的行为讲得透彻且连贯。这不仅帮读者知其然,更知其所以然,对于深入理解JavaScript的作用域链和执行上下文机制也大有裨益。

IT 累计浏览 18,261

深入理解Javascript之执行上下文(Execution Context)

这篇讲的是JavaScript中最核心但常被忽略的概念——执行上下文。作者从代码的运行环境切入,清晰地将执行上下文划分为全局、函数和Eval三种类型,并指出它是理解变量提升、作用域等行为的钥匙。 文章用一个函数调用图,生动展示了多个执行上下文是如何像栈一样被管理的:单线程的JavaScript引擎在执行代码时,每调用一个函数就会创建一个新的上下文并压栈,执行完毕后再弹出。这种“堆栈”模型解释了代码执行的严格顺序。 更深入地,作者剖析了执行上下文创建时的两个关键阶段。在真正的代码执行前,引擎会先进入“建立阶段”,完成变量与函数的声明、作用域链的构建以及this值的确定。这正解释了为什么函数内的变量可以在声明前被访问(值为undefined),而函数却可以立即调用。 通过对堆栈机制和建立阶段的拆解,文章把抽象的引擎内部行为变得可视化,帮助开发者从根本上理解代码的运行逻辑。

IT 累计浏览 3,460

javascript作用域和作用域链

这篇讲的是 JavaScript 开发者经常困惑的“作用域”到底是什么。作者从作用域链的实现机制切入,首先厘清了全局作用域和局部作用域的区别:哪些变量无处不在,哪些只在函数内部有效。特别点出了全局变量的“魔鬼”属性——效率低且污染环境,还警告了函数内部省略 `var` 声明会意外泄漏到全局作用域这个经典“坑”。 文章的核心在于剖析作用域链这个内部机制。它决定了变量查找的路径:引擎会从当前函数的作用域开始,逐层向外查找,直到全局作用域。这种由内向外的查找规则,直接关联到一个重要的性能优化点——标识符所在层级越深,访问速度越慢。因此,作者给出了一个实用的经验法则:将频繁访问的跨作用域对象(比如 `document`)先缓存到局部变量中,能显著提升运行效率。 对于想彻底搞懂闭包、变量提升等进阶概念的前端开发者来说,把这篇文章里作用域链的查找过程和“全局变量尽量少用”的原则理解透彻,是写出更干净、更高效代码的基础一步。

IT 累计浏览 2,820

从另外两道题说起

最近 JavaScript 题目挺火,Dmitry A. Soshnikov 也出了几道新题,还附带评分。本文没有泛泛而谈,而是精选了其中两道特别绕的题目,深入拆解了几个核心的 JavaScript 知识点。 作者从具体的题目出发,没有停留在解题本身,而是借题发挥,聚焦于作用域、执行上下文和闭包等概念在代码执行中是如何实际运作的。文章把抽象的语言规范,转化成了看得见、摸得着的执行流程。 通过这两道题的剖析,读者能更直观地理解,为什么某些代码会得出看似反直觉的结果,以及 JavaScript 引擎在背后做了哪些“看不见的工作”。这种通过具体题目来理解核心机制的方式,帮助开发者从根本上把握语言特性,写出更健壮的代码。

IT 累计浏览 3,260

Zakas解答Baranovskiy的JavaScript小测试

Zakas在Twitter上分享了Baranovskiy的一篇挑衅性文章《So, you think you know JavaScript?》,文章核心是一个看似简单的JavaScript小测验,由5段精心设计的代码片段组成。这个测试迅速在开发者社区引发了热烈讨论,包括Zakas本人在内的许多资深工程师都在这些陷阱题上栽了跟头,暴露出对一些JavaScript底层行为和边角特性的普遍误解。 作者Baranovskiy通过这个测验,并非要炫耀技巧,而是为了揭示一个事实:即使是有经验的开发者,也可能对语言的一些基础机制(如类型强制转换、作用域链、运算符优先级等)存在想当然的理解。Zakas的分享和参与解答,让这个讨论过程变得公开且富有启发性。文章的价值不在于找出“标准答案”,而是通过这些具体的错误案例,推动大家重新审视那些习以为常的代码写法背后的准确原理。 它提醒开发者,JavaScript的简洁语法下隐藏着不容忽视的复杂性。花时间理解这些细节,不仅能避免线上潜在的bug,更是深入掌握这门语言的必经之路。这篇分享就像是一个高质量的“代码体检”,值得每位JavaScript开发者用来自测和反思。

IT 累计浏览 2,421

可能被你忽略的 JavaScript 代码陷阱

这篇讲的是一段看似简单却布满陷阱的 JavaScript 代码。作者从一段只有几行的函数入手,揭示了新手乃至有经验的开发者都可能踩中的典型坑点。 这段代码首先在变量声明上就埋了雷:`var container = container` 试图对函数参数 `container` 重新声明,这在 JavaScript 中是多余的,且可能引发意料之外的变量遮蔽问题。更隐蔽的逻辑错误在于 `isLive` 的赋值,`config.isLive || true` 这种写法意味着,只要 `config.isLive` 为 falsy(比如 `false`),最终结果就会被错误地置为 `true`,完全违背了传入 `false` 的意图。此外,代码中直接引用了从未定义的全局变量 `g_foo`,这必然会导致程序抛出 `ReferenceError`。 这些陷阱共同指向了一个核心:对 JavaScript 语言基础特性的理解不够扎实。例如,短路运算符 `||` 的真实行为、变量声明的提升与作用域,以及对全局作用域污染的风险,都可能在日常编码中悄悄埋下隐患。文章通过具体案例,提醒开发者审视那些“习以为常”的写法,夯实基础才是写出健壮代码的根本。