变量作用域和函数作用域都涉及到变量值的变化,本文旨在让大家明白他们之间的区别

变量的作用域:

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

var n=999;
function f1(){
  console.log(n);
}
f1(); //

另一方面,在函数外部自然无法读取函数内的局部变量。

function f1(){
  var n=999;
}
consolg.log(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

function f1(){
 n=999;
}
f1();
consolg.log(n); //

函数的作用域:

先看一小段代码:

var scope="global";
function t(){
console.log(scope);
var scope="local"
console.log(scope);
}
t();

第一句输出的是: "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"

作用域链:

先来看一段代码:

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语句结束后,作用域链恢复正常。

JavaScript变量的作用域和函数的作用域的区别的更多相关文章

  1. 前端笔记知识点整合之JavaScript(四)关于函数、作用域、闭包那点事

    一.自定义函数function 函数就是功能.方法的封装.函数能够帮我们封装一段程序代码,这一段代码会具备某一项功能,函数在执行时,封装的这一段代码都会执行一次,实现某种功能.而且,函数可以多次调用. ...

  2. 前端笔记之JavaScript(四)关于函数、作用域、闭包那点事

    一.自定义函数function 函数就是功能.方法的封装.函数能够帮我们封装一段程序代码,这一段代码会具备某一项功能,函数在执行时,封装的这一段代码都会执行一次,实现某种功能.而且,函数可以多次调用. ...

  3. javascript变量声明提升和函数声明提升

    在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域.变量提升即将变量声明提升到它所在作用域的最开始的部分. JS的解析过程分为两个阶段:预 ...

  4. javascript 变量、常量 、 函数 声明

    声明变量: 方式一: 使用 var 定义变量,可在定义的同时赋值 或 不赋值 . 方式二: 直接使用[变量名 = 值]的形式,这会定义一个全局变量,但在严格模式下会出现引用错误.[不建议使用] 方式三 ...

  5. JavaScript变量、数据类型、函数

    #转载请留言联系 说在前面: JavaScript 是一种弱类型语言,javascript的变量类型由它的值来决定. JavaScript语句的末尾用 ; 结束.空格没有特殊意义. 1.JavaScr ...

  6. javascript 变量声明有var与无var 的区别

    1.在函数作用域内 加var定义的变量是局部变量,不加var定义的就成了全局变量.使用var定义var a = 'hello World';function bb(){var a = 'hello B ...

  7. 【转】javascript变量作用域、匿名函数及闭包

    下面这段话为摘抄,看到网上大多数人使用的是变量在使用的时候声明而不是在顶端声明,也可能考虑到js查找变量影响性能的问题,哪里用就在哪里声明,也很好. 在Javascript中,我们在写函数的时候往往需 ...

  8. [译]JavaScript:函数的作用域链

    原文:http://blogs.msdn.com/b/jscript/archive/2007/07/26/scope-chain-of-jscript-functions.aspx 在JavaScr ...

  9. C语言中变量和函数的作用域和链接属性

    C语言中变量和函数的作用域和链接属性 作用域 代码块作用域: 代码块指的是使用"{}"包围起来的部分. 在代码块中定义的变量,代码块之外是不能访问的. 代码块嵌套之后的变量作用域, ...

随机推荐

  1. Fiddler基本原理与抓取Andriod与IOS的App数据包

    Fiddler基本原理 Fiddler数据包的原理是Fiddler将自己设置为一个代理服务器,默认监听127.0.0.1:8888端口同时将浏览器的HTTP.HTTPS协议设置为使用代理服务器也就是使 ...

  2. Linux IPC System V 共享内存

    模型 #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> ftok() //获取key值 s ...

  3. 高性能MySQL笔记 第6章 查询性能优化

    6.1 为什么查询速度会慢   查询的生命周期大致可按照顺序来看:从客户端,到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端.其中“执行”可以认为是整个生命周期中最重要的阶段. ...

  4. raspberry pi2 智能小车源码及测试视频

    作者:XIAOBO QQ:463431476 转载请注明作者Python 源代码 import RPi.GPIO as GPIO  #human-computer-interaction import ...

  5. 【redis使用全解析】常见运维操作

    作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ 1.1 启动 1.1.1 启动redis $ redis-server redis.conf 常见选项: ./r ...

  6. [HOOLOO] zizaco/entrust 5.2.x-dev Class name must be a valid object or a string

    在使用laravel 5.1权限管理,使用  安装 zizaco/entrust 5.2.x-dev的时候执行 php artisan entrust:migration的时候报以下错误: [Symf ...

  7. JVM再了解了解

    转自 http://www.cnblogs.com/Coda/p/4331432.html 相信大家已经了解到Java具有跨平台的特性,可以“一次编译,到处运行”,在Windows下编写的程序,无需任 ...

  8. poj3278 Catch That Cow

    Catch That Cow Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 73973   Accepted: 23308 ...

  9. maya 专家模式

    maya中按ctrl + 空格 可以在普通模式与专家模式之间切换,如图 普通模式 按ctrl+空格后进入专家模式 来自为知笔记(Wiz)

  10. HTML 学习笔记 JavaScript (实现)

    HTML中的脚本 必须位于<script></script>标签之间 脚本可被放置在HTML页面的<body>和<head>部分中 <script ...