js作用域与作用域链
一直对Js的作用域有点迷糊,今天偶然读到JavaScript权威指南,立马被吸引住了,写的真不错。我看的是第六版本,相当的厚,大概1000多页,Js博大精深,要熟悉精通需要大毅力大功夫。
一:函数作用域
先看一小段代码:
- var scope="global";
- function t(){
- console.log(scope);
- var scope="local"
- console.log(scope);
- }
- t();
(PS: console.log()是firebug提供的调试工具,很好用,有兴趣的童鞋可以用下,比浏览器+alert好用多了)
第一句输出的是: "undefined",而不是 "global"
第二讲输出的是:"local"
你可能会认为第一句会输出:"global",因为代码还没执行var scope="local",所以肯定会输出“global"。
我说这想法完全没错,只不过用错了对象。我们首先要区分Javascript的函数作用域与我们熟知的C/C++等的块级作用域。
在C/C++中,花括号内中的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的。而Javascript压根没有块级作用域,而是函数作用域.
所谓函数作用域就是说:-》变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
所以根据函数作用域的意思,可以将上述代码重写如下:
- var scope="global";
- function t(){
- var scope;
- console.log(scope);
- scope="local"
- console.log(scope);
- }
- t();
我们可以看到,由于函数作用域的特性,局部变量在整个函数体始终是由定义的,我们可以将变量声明”提前“到函数体顶部,同时变量初始化还在原来位置。
为什么说Js没有块级作用域呢,有以下代码为证:
- var name="global";
- if(true){
- var name="local";
- console.log(name)
- }
- console.log(name);
都输出是“local",如果有块级作用域,明显if语句将创建局部变量name,并不会修改全局name,可是没有这样,所以Js没有块级作用域。
现在很好理解为什么会得出那样的结果了。scope声明覆盖了全局的scope,但是还没有赋值,所以输出:”undefined“。
所以下面的代码也就很好理解了。
- function t(flag){
- if(flag){
- var s="ifscope";
- for(var i=0;i<2;i++)
- ;
- }
- console.log(i);
- console.log(s);
- }
- t(true);
输出:2 ”ifscope"
二:变量作用域
还是首先看一段代码:
- function t(flag){
- if(flag){
- s="ifscope";
- for(var i=0;i<2;i++)
- ;
- }
- console.log(i);
- }
- t(true);
- console.log(s);
就是上面的翻版,知识将声明s中的var去掉。
程序会报错还是输出“ifscope"呢?
让我揭开谜底吧,会输出:”ifscope"
这主要是Js中没有用var声明的变量都是全局变量,而且是顶层对象的属性。
所以你用console.log(window.s)也是会输出“ifconfig"
当使用var声明一个变量时,创建的这个属性是不可配置的,也就是说无法通过delete运算符删除
var name=1 ->不可删除
sex=”girl“ ->可删除
this.age=22 ->可删除
三:作用域链
先来看一段代码:
- name="lwy";
- function t(){
- var name="tlwy";
- function s(){
- var name="slwy";
- console.log(name);
- }
- function ss(){
- console.log(name);
- }
- s();
- ss();
- }
- t();
当执行s时,将创建函数s的执行环境(调用对象),并将该对象置于链表开头,然后将函数t的调用对象链接在之后,最后是全局对象。然后从链表开头寻找变量name,很明显
name是"slwy"。
但执行ss()时,作用域链是: ss()->t()->window,所以name是”tlwy"
下面看一个很容易犯错的例子:
- <html>
- <head>
- <script type="text/javascript">
- function buttonInit(){
- for(var i=1;i<4;i++){
- var b=document.getElementById("button"+i);
- b.addEventListener("click",function(){ alert("Button"+i);},false);
- }
- }
- window.onload=buttonInit;
- </script>
- </head>
- <body>
- <button id="button1">Button1</button>
- <button id="button2">Button2</button>
- <button id="button3">Button3</button>
- </body>
- </html>
当文档加载完毕,给几个按钮注册点击事件,当我们点击按钮时,会弹出什么提示框呢?
很容易犯错,对是的,三个按钮都是弹出:"Button4",你答对了吗?
当注册事件结束后,i的值为4,当点击按钮时,事件函数即function(){ alert("Button"+i);}这个匿名函数中没有i,根据作用域链,所以到buttonInit函数中找,此时i的值为4,
所以弹出”button4“。
四:with语句
说到作用域链,不得不说with语句。with语句主要用来临时扩展作用域链,将语句中的对象添加到作用域的头部。
看下面代码
- person={name:"yhb",age:22,height:175,wife:{name:"lwy",age:21}};
- with(person.wife){
- console.log(name);
- }
with语句将person.wife添加到当前作用域链的头部,所以输出的就是:“lwy".
with语句结束后,作用域链恢复正常。
js作用域与作用域链的更多相关文章
- 了解 JS 作用域与作用域链
(1)作用域 一个变量的作用域(scope)是程序源代码中定义的这个变量的区域. 1. 在JS中使用的是词法作用域(lexical scope) 不在任何函数内声明的变量(函数内省略var的也算全局) ...
- JS的作用域和作用域链
每个函数都有自己的作用域,当执行流进入一个函数时,函数就会被推入栈中,而在函数执行之后,栈将其执行环境弹出,把控制权放回给之前的作用域,全局作用域是最外围的一个作用域,因此,所有全局变量和函数都是作为 ...
- 第十八篇 js高级知识---作用域链
一直有想法去写写js方面的东西,我个人是最喜欢js这门语言,喜欢的他的自由和强大,虽然作为脚本语言有很多限制的地方,但也不失为一个好的语言,尤其是在H5出现之后.下面开始说说js的方面的东西,由于自己 ...
- js学习--变量作用域和作用域链
作为一名菜鸟的我,每天学点的感觉还是不错的.今天学习闭包的过程中看到作用域与作用域链这两个概念,我觉得作为一名有追求的小白,有必要详细了解下. 变量的作用域 就js变量而言,有全局变量和局部变量.这里 ...
- js 作用域,作用域链,闭包
什么是作用域? 作用域是一种规则,在代码编译阶段就确定了,规定了变量与函数的可被访问的范围.全局变量拥有全局作用域,局部变量则拥有局部作用域. js是一种没有块级作用域的语言(包括if.for等语句的 ...
- Js 作用域与作用域链与执行上下文不得不说的故事 ⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄
最近在研究Js,发现自己对作用域,作用域链,活动对象这几个概念,理解得不是很清楚,所以拜读了@田小计划大神的博客与其他文章,受益匪浅,写这篇随笔算是自己的读书笔记吧~. 作用域 首先明确一个概念,js ...
- 理解js中的作用域,作用域链以及闭包
作用域变量作用域的类型:全局变量和局部变量全局作用域对于最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的 <script> var outerVar = " ...
- js对象系列【二】深入理解js函数,详解作用域与作用域链。
这次说一下对象具体的一个实例:函数,以及其对应的作用域与作用域链.简单的东西大家查下API就行了,这里我更多的是分享自己的理解与技巧.对于作用域和作用域链,相信绝大多数朋友看了我的分享都能基本理解,少 ...
- js基础梳理-如何理解作用域和作用域链?
本文重点是要梳理执行上下文的生命周期中的建立作用域链,在此之前,先回顾下关于作用域的一些知识. 1.什么是作用域(scope)? 在<JavaScritp高级程序设计>中并没有找到确切的关 ...
- JS作用域,作用域,作用链详解
前言 通过本文,你大概明白作用域,作用域链是什么,毕竟这也算JS中的基本概念. 一.作用域(scope) 什么是作用域,你可以理解为你所声明变量的可用范围,我在某个范围内申明了一个变量,且这个变量 ...
随机推荐
- Linux学习笔记18——信号1
一 信号的基本概念 信号:是向进程发送的软件通知,通知进程有事件发生. 生成:表示一个信号的产生. 捕获:表示接收到一个信号. 信号的寿命:信号的生成和传递之间的时间间隔. 挂起的信号:已经生成但还未 ...
- Unity Skin Shader Optimized
Shader "Skin Shader" { Properties { _MainTex ("Diffuse (RGB)", 2D) = "white ...
- iOS类的继承关系
- nginx主配置文件 在那找怎么打开
- 如何以非 root 用户将应用绑定到 80 端口-ssh 篇 » 社区 » Ruby China
如何以非 root 用户将应用绑定到 80 端口-ssh 篇 » 社区 » Ruby China 如何以非 root 用户将应用绑定到 80 端口-ssh 篇
- JavaWeb学习总结(1-53)
本文转自孤傲苍狼 博客,JavaWeb学习总结 专题,一共53集,讲解简洁清晰,适合入门,链接和截图如下 http://www.cnblogs.com/xdp-gacl/category/574705 ...
- myisam MySQL 锁问题
2016-07-23 (点击上方公众号,可快速关注) 来源:阿里云 RDS - 数据库内核组 链接:http://mysql.taobao.org/monthly/2016/03/10/ 前言 最近 ...
- uva10622 Perfect P-th Powers
留坑(p.343) 完全不知道哪里有问题qwq 从31向下开始枚举p,二分找存在性,或者数学函数什么的也兹辞啊 #include<cstdio> #include<cstring&g ...
- C++程序在debug模式下遇到Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call问题。
今天遇到一个Access Violation的crash,只看crash call stack没有找到更多的线索,于是在debug模式下又跑了一遍,遇到了如下的一个debug的错误提示框: 这个是什么 ...
- 听听Matt Rogish说怎么面试程序员
Google的人力运营高级副总裁Laszlo Bock在一次采访中说Google发现在面试程序员时问智力题完全是浪费时间,Matt Rogish在他的这篇博客How to Interview Prog ...