js中的作用域和作用域链

作用域就是变量与函数的可访问范围。在js中只有 全局作用域函数作用域 ,并没有块级作用域。

全局作用域

在所有函数外定义的变量、声明的函数就是全局作用域,在全部环境下都可以访问。

var a = 111;function fn(){console.log(a);
}fn(); // 打印了111

在函数中没有使用 var关键词声明的变量

function fn(){a = 111;
}fn();console.log( a ); // 打印了111

作为 window 对象的属性赋值

function fn(){window.a = 111;
}fn();console.log(a); // 111 ,同样可以拿到a变量

注:所有的全局变量都是 window对象的属性,可以通过 window[propertyName]来访问

函数用域

js中函数具有自己的作用域,在函数中使用var关键词声明的变量函数外是访问不到的,但是在函数中却可以很方便的访问到函数外定义的变量。在其中起作用的就是函数的作用域链。

作用域链的作用就是让函数在运行的时候查找需要用到的标识符,当console.log(a)的时候就会在作用域链中查找a如果找到了就返回找到的值,若没有找到就会报错,这个和在对象中查找不存在的属性只会返回undefined不同。

var a = 111;function fn(){var b = 222;console.log(a);
}fn(c); // 111
console.log(b); // ReferenceError: b is not defined 访问为定义变量的错误

在定义函数的时候js引擎会为函数生成一个[[scope]]属性(函数也是对象所以可以有属性),这个属性存放着当前执行环境的作用域链。

当函数执行的时候会创建一个执行上下文,执行上下文定义了函数的执行环境。每个执行环境都有自己的作用域链(不是函数定义时的[[scope]]属性)用于标识符解析,执行上下文复制函数定义时被定义的[[scope]]属性值到自己的作用域链上,并且会创建一个 **活动对象(对象包括arugments,this,声明的变量等)**添加到自身作用域链的顶端。
##函数定义
函数定义时的作用域属性

函数执行

函数执行时的作用域链

闭包

function fn(){var c = 111;return function bibao(){return c;}
}var d = fn();  // 这时候的d是fn内部定义的函数bibaoconsole.log( d() ); // 函数bibao 返回了fn的内部变量c,所以在全局环境下就可以在外部访问fn内部变量,这就是闭包。
  1. 首先定义了函数fn,fn生成了[[scope]]属性,window对象在该属性中。
  2. 执行fn 的时候 创建了一个fn的执行上下文,执行上下文中有this,还有自己的作用域链,作用域链中包括了 fn 的[[scope]]属性,同时创建了一个变量对象,变量对象中包括arguments对象、 变量c等等。
  3. 在fn函数中定义函数bibao,生成bibao的[[scope]]属性,该属性会复制当前执行上下文的作用域链到自身。
  4. 当执行fn的时候返回bibao函数,注意bibao函数的[[scope]]属性中是有fn的执行环境的作用域链。
  5. 执行d的时候也就是执行了bibao函数。
  6. 执行bibao函数的时候bibao函数会创建一个执行的上下文,上下文会复制bibao函数的[[scope]]属性来创建自己的作用域链,同时创建一个活动对象来添加到自己的作用域链顶端。
  7. 返回 变量c 这个c并不在 bibao 函数自己的活动对象上,但是却在bibao函数执行上下文的作用域链里面,所以可以访问到。

以上就是我理解的闭包的形成。

按照上面的理解js中闭包存在于很多地方,只要在函数中访问上级作用域中的变量就形成了闭包。

var a = 111;function fn(){console.log(a);
}fn(); // 111 这里打印出来的111也不是自身活动对象上的变量,是上级作用域的变量,所以这也是闭包

#改变作用域链

with(obj)

将对象推入作用域链前端,让with代码块中可以访问到相关的变量。

with({a: '111'}){console.log(a); // 111
}

try{}catch(ex){}

然后把异常对象推入一个可变对象并置于作用域的头部

函数声明和函数表达式

在js中使用这两种方法定义函数有显著的差别。

函数声明可以放在函数调用的后面,也就是说可以先调用函数再声明函数。但是函数表达式的定义放在了函数调用后面的话就会报错。

fn(); // 会报错var fn = function(){console.log('111');
};

实际执行的是

var fn;fn(); // 相当于undefined()fn = function(){console.log('111');
}

用函数表达式正确的写法是先声明赋值之后再调用。

var fn = function(){console.log('111');
};fn();

下面是函数声明的方式。

fn();function fn(){console.log('22222');
}

实际执行可以看成

function fn(){console.log('22222');
}fn();

为甚会这样呢?js会把声明提前(函数声明和变量声明),但是赋值并不会提前,所以才会看到上面一系列奇怪的现象。

根据先定义后使用的规范,建议使用函数表达式,不使用函数声明。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362250.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CryEngine3 引擎非商业用途将免费

CryEngine3引擎非商业用途将免费:8月发布 http://t.cn/hdEr45】Crytek日前宣布将在今年8月免费推出CryEngine3引擎的开发包,登录Crytek官网注册,签署保密协议保证不将CryEngine3用作商业用途,就可获得CryEngine3软件授权。Crytek官网上的一份…

vue打包后不使用服务器直接访问方法

根据官网打包执行npm run build 后dist文件夹打开的index.html 是空白 需要开启http服务器才能访问,以下是解决办法 1、找到config文件夹下的index文件 修改成 2、找到build文件夹下的until文件 修改成 然后执行npm run build重新打包下就ok了 更多专业前端知…

IntelliJ中的键盘快捷键

我上周参加了Hadi Hariri在JavaOne上的演讲。 他介绍了很多我不知道的IntelliJ键盘快捷键。 非常有用的谈话。 我在下面列出了一些最有用的。 Cmd-1:将焦点移到“项目”窗口 在此输入任何类名(包括使用Camel Case,例如HW来查找HelloWorld&a…

OpenStack虚机网卡的创建过程

原文:https://www.sdnlab.com/20286.htmlOpenStack最基本和常用的操作就是启动虚机。虚机启动的过程中涉及很多内容,其中非常重要的一个环节就是创建并绑定虚机的虚拟网卡。虚机的创建和管理是Nova的任务,虚机网络的创建和管理是Neutron的任务…

js中的原型与原型链

js的学习有三座大山, 原型/原型链 、 作用域/闭包 、 异步/单线程,这三个知识点虽然基础但是入门时理解起来比较困难,本文先整理总结原型和原型链这一知识点。 1. 原型链怎么来的?对象的原型和function的prototype属性有什么关系…

线性表--算法设计题2.29

已知A,B和C为三个递增有序的线性表,现要求对A表作如下操作:删去那些既在B表中出现又在C表中出现的元素。试对顺序表编写实现上述操作的算法.(注意:题中没有特别指明同一表中的元素值各不相同)。C code: #in…

HTML5 audio 如何实现播放多个MP3音频

<audio>标签是HTML5中的新标签&#xff0c;定义声音用于嵌入音频内容&#xff0c;比如音乐或其他音频流。用的比较多音频格式是.mp3。 <audio>标签常用属性如下表 属性值描述autoplayautoplay添加该属性后&#xff0c;音频会自动播放controlscontrols设置后&…

Java代码中的典型错误

该页面包含在与我一起工作的人的Java代码中看到的最典型的错误。 静态分析&#xff08;出于明显的原因&#xff0c;我们使用查询无法捕获所有错误&#xff0c;这就是为什么我决定在此处列出所有错误的原因。 如果您要在此处添加其他内容&#xff0c;请告诉我&#xff0c;我们将…

windwos下ntp服务器配置 arm平台ntp客户端获取同步时间

项目需要使用同步时间&#xff0c;在arm-linux开发板上&#xff0c;移植了ntp客户端&#xff0c;查看了一些资料&#xff0c;最终发现使用windows自带的ntp服务器比较方便&#xff0c;而且很靠谱&#xff0c;使用配置了一番&#xff0c;已经能够正常使用 详细步骤&#xff1a; …

css 控制图片最大宽度

CSS 限制图片最大宽度 (本文来自本站原创&#xff0c;转载请务必注明出处&#xff01;)我们在制作一个网页的时候&#xff0c;经常要对一个区域里可能出现的图片的宽度进行限制&#xff0c;不然它可能会把页面撑得很烂很烂。如果你采用固定宽度&#xff0c;长度来设置的话&…

BOM(Browser Object Model)

BOM&#xff08;浏览器对象模型&#xff09;&#xff0c;提供了一系列操作浏览器&#xff0c;获取浏览器信息的接口。这些接口在平时的工作中会经常用到&#xff0c;例如当前页面的刷新&#xff0c;获取url的参数等等。 注&#xff1a;图片来自 http://www.dreamdu.com/javascr…

入门 IT 行业,该具备哪些技能?

对于刚开始进入IT的新人来说&#xff0c;“必备技能”往往意味着一个长长的、标有重要度的学习列表&#xff0c;但是过长的列表通常会导致新人不知如何开始学习&#xff0c;压力倍增。本文尝试列举出最重要的几个技能&#xff0c;也期望通过此列表能给新人一个比较明确的学习重…

实验七作业

Part 1:验证性实验 将line29&#xff1a;for(i0;i<N;i)改为while(!feof(fp)) // 从文本文件file1.dat中读取数据&#xff0c;找出最高分和最低分学生信息&#xff0c;并输出在屏幕上 #include <stdio.h> #include <stdlib.h>#define N 10// 定义一个结构体类型…

块级格式化上下文(Block Formatting Context)

CSS块级格式化上下文是块级盒子的一种能力&#xff0c;这种能力并不是直接通过css属性声明而获得的&#xff0c;而是添加css的一部分相关属性之后自动获得的能力&#xff0c;也就是说没有一个明确的属性就是生成块级格式化上下文的。 块级格式化上下文的能力就是让具有该能力的…

这是最后的讨论!

Pun打算……让我们讨论Java final 。 最近&#xff0c;我们广受欢迎的博客文章“编码Java时的十个微妙的最佳实践”在JavaWorld的摘要和链接中有了很大的复兴&#xff0c;并提出了一组新的评论。 尤其是&#xff0c;JavaWorld编辑对我们对Java关键字“ final ”的观点提出了质…

前端性能优化方法总结

一个网站前端性能的好坏很大程度上影响了用户愿不愿意使用访问这个网站&#xff0c;因此对前端进行性能优化是个很重要的事情。  对于前端性能优化这个问题&#xff0c;主要学习自yahoo前端性能团队总结的35条黄金定律总结&#xff0c;觉得很全很赞&#xff0c;做个学习总结和…

JS中的数据类型转换

ES5中一共有6种数据类型&#xff0c;其中5种基本类型&#xff08;String、Number、Boolean、Null、Undefined&#xff09;&#xff0c;1种引用类型&#xff08;Object&#xff09;。基本类型值可以相互换转换&#xff0c;并且引用类型值也可以通过某种方式转换成基本类型值。 …

拯救我的操作系统

最近公司新装操作系统image都强制装win7&#xff0c;公司电脑一直拖着没有升级&#xff0c;家里也一直是用番茄花园版的xp&#xff0c;突然心血来潮去买了个win7的碟&#xff0c;心想最好是破解版的&#xff0c;回来一装&#xff0c;发现是所谓的旗舰版的&#xff0c;可恶的是这…

Hazelcast的MapLoader陷阱

Hazelcast提供的核心数据结构之一是IMap<K, V> &#xff0c;它扩展了java.util.concurrent.ConcurrentMap它基本上是一个分布式地图&#xff0c;通常用作缓存。 您可以将此类地图配置为使用自定义MapLoader<K, V> -每次尝试从该地图&#xff08;通过键&#xff09;…

《Android开发从零开始》——22.数据存储(1)

本节课的主要内容有&#xff1a;1.介绍Android中数据存储方式2.介绍SQLite3.讲解SQLite数据类型4.讲解基本SQL命令 课程下载地址&#xff1a;http://u.115.com/file/clc4te8w课件及源码下载地址&#xff1a;http://u.115.com/file/clc41tt5转载于:https://www.cnblogs.com/cool…