JavaScript作用域详解
作用域在JavaScript中是非常重要的概念,理解了它对更深入地理解闭包等概念都有很大的帮助,这篇文章就来谈谈我对作用域的理解。
一、全局作用域与局部作用域
在JavaScript中没有块级作用域的概念,它的作用域都是以函数作为划分的。JavaScript的作用域分为全局作用域和局部作用域。能在代码中的任何地方访问到的变量具有全局作用域,只能在固定代码段,例如函数内部,访问到的变量具有局部作用域。
全局作用域主要包括:1. 定义在最外层的变量和函数 2. 没经过声明,直接定义的变量,及不包含var关键字的变量。3. window对象的属性都具有全局作用局。例如:window.setTimeout, window.location
局部作用域主要包括: 1. 函数内部通过var关键字声明的变量 2.函数传入的参数
var foo = 'global'; //全局变量
function(bar) {
var goo = 'inside'; //局部变量
env = 1; //全局变量
}
二、作用域链
作用域链定义了函数执行时可访问到的变量的范围。一个函数的作用域链创建分为两个步骤:一是在函数定义时创建的[[scope]]属性中包含的对象,二是在函数执行时创建的活动对象。
1. [[scope]]属性
函数的[[scope]]属性中包含的是函数在创建时所在的作用域中可访问的对象。只有JavaScript引擎可以访问到。例如:
var foo = 1;
function add(num1, num2) {
var sum = num1 + num2;
return sum;
}
add(foo, 1);
在函数add定义的时候,创建了[[scope]]内部属性,因为add定义在全局作用域中,所以[[scope]]属性中包含了所有的全局变量。
2. 活动对象
函数每次调用都会创建一个执行上下文,这个执行上下文会有自己的作用域链,也就是函数的作用域链。作用域链被创建时,会初始化为[[scope]]属性中包含的对象。接下来,将函数传入的参数arguments,以及函数中声明的局部变量集合起来,组成了活动对象。并把活动对象压入作用域链的最前端。在本例中add函数的活动对象主要包括传入的参数num1、num2以及局部变量sum。
此后在进行变量名解析时,会从作用域链的顶端开始往下查找,找到则返回对应变量,找不到返回错误信息。
当函数执行完毕,执行上下文会被销毁,活动对象也随之销毁。函数的每次调用都会创建新的执行上下文,并关联新的作用域链。
三、改变作用域
要想人为地改变函数的作用域链有两种方法:with语句和try-catch中的catch语句。
1. width语句
当运行到width语句时,会把width的对象的所有属性包裹成一个对象压入作用域链的最前端。
function create() {
width(document) {
var list = createElement('li');
list.onclick = function() {
//dosomething
}
};
}
在这个例子中会在当前create函数的作用域链的最前端加入document包含的所有属性,例如例子中用到的createElement方法。这样写貌似代码更简洁了,可是却造成了性能问题。因为作用域链的最前端是with对象的所有属性方法,这样函数内部的局部变量都变成作用域链中的第二级了,要查找到局部变量需要先遍历第一级,使查找时间变长。所以一般来讲程序中尽量不要出现with语句。
2. catch 语句
使用try-catch语句当遇到异常跳到catch语句中时,会把catch到的错误对象压入作用域链的最前端。
try{
dosomething
} catch(er) {
alert(er);
}
如上例,当运行到catch语句时,会把er对象压入作用域链的最前端。
三、变量声明提升
JavaScript会提升变量声明,被提升的声明包括var表达式和function函数声明,它们会被提升到当前作用域的最顶部。
bar();
var bar = function() {};
var someValue = 42; test();
function test(data) {
if(false) {
goo = 1;
} else {
var goo = 2;
}
for(var i=0; i<100; i++) {
var e = data[i];
}
}
如上例子,在变量提升后会变成:
var bar, someValue; //var 表达式声明被提升,但是赋值语句没有跟着提升,现在它们的值是undefined //函数声明被提升
function test(data) {
var goo, i, e; //局部变量的声明也会被提升,
if(false) {
goo = 1;
} else {
goo = 2;
}
for(i=0; i<100; i++) {
e = data[i];
}
} bar(); //出错,因为bar的值还是undefined
bar = function() {}; //赋值语句没有提升
someValue = 42;
test();
变量声明提升有时会带来一些不容易发现的问题,例如在没有提升前函数foo的false语句看起来是要改变全局变量goo,但是提升后可以清晰地看到它其实改变的是局部变量goo。对于这些情况一定到多注意。我认为能减少这类错误的方法是在函数内部将要用到的局部变量都先声明在最前面,手动提升。而函数声明尽量使用function声明方式而不是赋值语句,这样无论调用语句在前面还是后面都不会出错。
JavaScript作用域详解的更多相关文章
- javascript 作用域详解
作用域理解:定义的变量.函数生效的范围.javascript 有全局作用域和函数作用域两种.注:es6实现let 块级作用域不是js原生的,底层同样是通过var实现的.如果想了解具体细节,请访问bab ...
- Javascript作用域详解。
javascript的作用域 是按照 函数来划分的. 网址:http://www.cnblogs.com/rubylouvre/archive/2009/08/21/1551270.html
- javascript中的this作用域详解
javascript中的this作用域详解 Javascript中this的指向一直是困扰我很久的问题,在使用中出错的机率也非常大.在面向对象语言中,它代表了当前对象的一个引用,而在js中却经常让我觉 ...
- JavaScript事件详解-jQuery的事件实现(三)
正文 本文所涉及到的jQuery版本是3.1.1,可以在压缩包中找到event模块.该篇算是阅读笔记,jQuery代码太长.... Dean Edward的addEvent.js 相对于zepto的e ...
- JavaScript事件详解-Zepto的事件实现(二)【新增fastclick阅读笔记】
正文 作者打字速度实在不咋地,源码部分就用图片代替了,都是截图,本文讲解的Zepto版本是1.2.0,在该版本中的event模块与1.1.6基本一致.此文的fastclick理解上在看过博客园各个大神 ...
- JavaScript正则表达式详解(一)正则表达式入门
JavaScript正则表达式是很多JavaScript开发人员比较头疼的事情,也很多人不愿意学习,只是必要的时候上网查一下就可以啦~本文中详细的把JavaScript正则表达式的用法进行了列表,希望 ...
- JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解
二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...
- PHP常量、变量作用域详解(一)
PHP 中的每个变量都有一个针对它的作用域,它是指可以在其中访问变量(从而访问它的值)的一个领域.对于初学者来说,变量的作用域是它们所驻留的页面.因此, 如果你定义了 $var,页面余下部分就可以访问 ...
- PHP变量作用域详解(二)
学过C的人用PHP的时候一般会相当顺手,而且感到PHP太方便太轻松.但在变量作用域这方面却与C有不同的地方,搞不好会相当郁闷,就找不到错误所在.昨晚就与到这么一个问题,是全局变量在函数中的问题.今天搜 ...
随机推荐
- MySQL中函数CONCAT及GROUP_CONCAT函数的使用
一.CONCAT()函数 CONCAT()函数用于将多个字符串连接成一个字符串. 以数据表[user]作为实例: SELECT USER_NAME, SEX FROM USER WHERE USER ...
- 一条跨库更新数据的sql
UPDATE [db1].[dbo].[R_ResAndBook] SET SectionID=TT2.newsecidFROM [SmartCampus].[dbo].[R_ResAndBo ...
- java aop 日志打印 正则设置
package tz.lion.Utils.aop; import com.alibaba.fastjson.JSON;import org.springframework.web.multipart ...
- 读书笔记 Week7 2018-4-19
<构建之法> 第十二章 用户体验 读书笔记 首先不得不说,现如今大部分的电脑使用者,都被微软的图形化界面把口味养刁了.当然,包括我自己.无论是在微机原理上级的时候使用那些带着浓郁的上世纪八 ...
- 83. Remove Duplicates from Sorted List (List)
Given a sorted linked list, delete all duplicates such that each element appear only once. For examp ...
- 什么是展uv
uvw是对应三维模型x.y.z坐标,就像模型的皮肤一样,为了便于绘制贴图,需要将UV尽量展平 展UV就是把你建好的模型展开成平面,别人就可以在那平面上做材质,皮肤等,这些东西.例如展一个正方体的UV, ...
- Oracle 日志报错导致的 “没有登录” 问题
遇到的问题是日志空间满了,导致Oracle无法登陆,但用PL/SQL登录仅会提示“没有登录” # 首先检查日志空间是否满了,并删除过期日志 rman target sysdba/password@or ...
- 搭建yum本地源_阿里云CentOS服务器初始化设置
CentOS服务器初始化设置其实不分阿里云或其它服务器了,操作配置过程与步骤也差不多一.挂载硬盘 1.磁盘分区 fdisk -l #查看设备,一般可以看到设备名为/dev/xvdb fdisk /de ...
- 如何申请新浪SAE,发布自己的网站
你是否会看见诸如(***.sinaapp.com)类的域名?是否和新浪有什么关系?抑或想要一个免费的空间展示自己的个人主页;没问题,下面我来分享一下SAE的申请流程吧! 首先,打开SAE(http:/ ...
- jsp页面数据分页模仿百度分页效果
<%@page import="web09.shop.DBUtil"%> <%@page import="java.sql.ResultSet" ...