好程序员web前端带你了解JS的作用域链

简介: 好程序员web前端带你了解JS的作用域链,我们都知道js是一个基于对象的语言,系统内置各种对象。 而window作为一个天然存在的全局对象,它承担了所有全局资源的存储。 我们使用的任何全局变量,都是window下的。

好程序员web前端带你了解JS的作用域链,我们都知道js是一个基于对象的语言,系统内置各种对象。
 
而window作为一个天然存在的全局对象,它承担了所有全局资源的存储。
 
我们使用的任何全局变量,都是window下的。也就是说,在js中,实际上没有任何对象、方法是可以独立的,它们必须依赖于某个对象才可以被访问或执行。
 
就像alert(),它的完整写法是window.alert()
parseInt(), 完整写法是window.parseInt()
 
所有放在window对象下的资源,访问时可以默认省略window
 
但有一种情况非常特殊,例如函数中的局部变量:
function Person(){
       var name = “abc”;
}
当我们试图访问这个name属性时
console.log(newPerson().name); 
结果是undefined
我们只能在函数内部访问:
function Person(){
       var name = “abc”;
       console.log(name);
}
这种属性,在构造函数中,也被称为私有属性,我们必须提供一种对外公开的方法才可以被外界访问。例如:
function Person(){
       var name = “abc”;
       this.getName = function(){
       returnname;
}
this.setName= function(_name){
       name = _name;
}
}
这是一个典型的作用域问题, 似乎我们每个人都知道。
 
但这似乎也违反了我们的一个常识:那就是在js中,所有资源都必须依赖对象才能存在,不可独立使用。比如说:
function aaa(){
       function bbb(){  }
       bbb();
}
这段代码看上去并没有错,但是请问bbb这个函数为什么可以独立存在呢?如果我们把它换成这样:
function aaa(){
       function bbb(){  }
       window.bbb();
}
结果是运行错误!
 
那如果换成这样呢?
function aaa(){
       function bbb(){  }
       this.bbb();
}
结果还是运行错误!
 
那么我们不禁要发问了,bbb这个函数到底是属于哪个对象的?
 
当我们在调用一个函数的时候,浏览器会为这个函数的执行开辟一块内存区域用来存储这个方法在执行的临时数据。而对象作为js的基本存储单位,因此,临时数据实际上都被保存到了一个对象当中,这个对象,就是我们平时所说的执行上下文环境
 
当我们调用aaa函数时,例如window.aaa()
浏览器会为这一次函数的执行,创建一个执行上下文环境对象,我们暂时给它起个名字,叫做contextAAA吧,当然它是临时的,因为函数执行完它也就消失了。
 
那我们的代码实际上会变成这样:
function aaa(){
       function bbb(){   }
       contextAAA.bbb();
}
尽管contextAAA对象是看不见的,但它确实存在。
 
而当我们执行bbb函数时,浏览器会再次为这一次函数调用创建一个临时的执行上下文环境,我们暂且叫它contextBBB
那么contextAAA 和contextBBB以及window之间会形成链条关系,
举个例子来说明吧
var num = 888;
function aaa(){
       var num = 100;
       function bbb(){
       var num= 200;
       console.log(num);
}
bbb();
}
aaa();
那么contextAAA 如下:
contextAAA = {
       num :100,
       bbb : function(){ … },
       parentContext: window//父级上下文对象
}
那么contextBBB如下:
contextBBB = {
       num : 200,
       parentContext: contextAAA //父级上下文对象
}
因此我们发现,在父级上下文对象中,我们没有办法访问到子级上下对象,这是一个单向链表,这就是全局不能访问局部的原因。
 
而bbb函数中打印出的num应该是多少呢?这取决在上下文对象中的查找顺序,顺序大概是这样的:
首先在当前上下文对象contextBBB中,找一下有没有num变量,找到就直接打印。以我们目前的代码看,结果应该是200
我们把代码改造一下:
var num= 888;
function aaa(){
       var num = 100;
       function bbb(){
       console.log(num);
}
bbb();
}
aaa();
由于这次在contextBBB对象中找不到num变量了,因此它会从父级上下文对象中查找,也就是contextAAA里面的num,因此打印的结果是100;
我们再把代码改造一下
var num= 888;
function aaa(){
       function bbb(){
       console.log(num);
}
bbb();
}
aaa();
由于这次连contextAAA对象里也找不到了,会再次向它的父级上下文对象,也就是window查找,因此打印结果是888
 
contextAAA和contextBBB的父子关系,在你写代码的一刻就决定了,这就是作用域。
function aaa(){
       var num = 10;

       function bbb(){  console.log(num);  }
}
而代码执行时,产生的上下文对象,是链表的关系。这就是我们所说的作用域链,它的原理跟原型链是一样的。
_17
理解了这一点,也能弄明白闭包的原理。
function aaa(){
       var num = 10;
       return functionbbb(){  console.log(num);  }
}
aaa( )( )
尽管bbb函数通过return在全局范围被执行了,但作用域的链表关系并没有发生改变,因此,bbb函数依然可以访问num这个局部变量。

目录
打赏
0
0
0
0
49
分享
相关文章
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
js的作用域作用域链
【10月更文挑战第29天】理解JavaScript的作用域和作用域链对于正确理解变量的访问和生命周期、避免变量命名冲突以及编写高质量的JavaScript代码都具有重要意义。在实际开发中,需要合理地利用作用域和作用域链来组织代码结构,提高代码的可读性和可维护性。
|
23天前
|
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
40 1
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
探索现代Web应用的微前端架构
【10月更文挑战第40天】在数字时代的浪潮中,Web应用的发展日益复杂多变。微前端架构作为一种新兴的设计理念,正逐步改变着传统的单一前端开发模式。本文将深入探讨微前端的核心概念、实现原理及其在实际项目中的应用,同时通过一个简单的代码示例,揭示如何将一个庞大的前端工程拆分成小而美的模块,进而提升项目的可维护性、可扩展性和开发效率。
springboot解决js前端跨域问题,javascript跨域问题解决
本文介绍了如何在Spring Boot项目中编写Filter过滤器以处理跨域问题,并通过一个示例展示了使用JavaScript进行跨域请求的方法。首先,在Spring Boot应用中添加一个实现了`Filter`接口的类,设置响应头允许所有来源的跨域请求。接着,通过一个简单的HTML页面和jQuery发送AJAX请求到指定URL,验证跨域请求是否成功。文中还提供了请求成功的响应数据样例及请求效果截图。
springboot解决js前端跨域问题,javascript跨域问题解决
HTML与CSS在Web组件化中的核心作用及前端技术趋势
本文探讨了HTML与CSS在Web组件化中的核心作用及前端技术趋势。从结构定义、语义化到样式封装与布局控制,两者不仅提升了代码复用率和可维护性,还通过响应式设计、动态样式等技术增强了用户体验。面对兼容性、代码复杂度等挑战,文章提出了相应的解决策略,强调了持续创新的重要性,旨在构建高效、灵活的Web应用。
71 6
使用Node.js创建一个简单的Web服务器
使用Node.js创建一个简单的Web服务器
JavaScript和TypeScript的未来发展趋势及其在Web开发中的应用前景
本文探讨了JavaScript和TypeScript的未来发展趋势及其在Web开发中的应用前景。JavaScript将注重性能优化、跨平台开发、AI融合及WebAssembly整合;TypeScript则强调与框架整合、强类型检查、前端工程化及WebAssembly的深度结合。两者结合发展,特别是在Vue 3.0中完全采用TypeScript编写,预示着未来的Web开发将更加高效、可靠。
120 4
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
74 2
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
86 4

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等