首页 > javascript变量声明 及作用域

javascript变量声明 及作用域

javascript变量声明提升(hoisting)

 http://openwares.net/js/javascript_declaration_hoisting.html 可能要FQ一下

javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面。

先看一段代码

1
2
3
4
5
var v = "hello";
(function(){
  console.log(v);
  var v = "world";
})();

这段代码运行的结果是什么呢?

答案是:undefined

这段代码说明了两个问题,

第一,function作用域里的变量v遮盖了上层作用域变量v。代码做少些变动

1
2
3
4
5
var v = "hello";
if(true){
  console.log(v);
  var v = "world";
}

输出结果为”hello”,说明javascript是没有块级作用域的函数是JavaScript中唯一拥有自身作用域的结构。

第二,在function作用域内,变量v的声明被提升了。所以最初的代码相当于:

1
2
3
4
5
6
var v = "hello";
(function(){
  var v; //declaration hoisting
  console.log(v);
  v = "world";
})();

声明、定义与初始化

声明宣称一个名字的存在,定义则为这个名字分配存储空间,而初始化则是为名字分配的存储空间赋初值。

用C++来表述这三个概念

1
2
3
extern int i;//这是声明,表明名字i在某处已经存在了
int i;//这是声明并定义名字i,为i分配存储空间
i = 0;//这是初始化名字i,为其赋初值为0

javascript中则是这样

1
2
var v;//声明变量v
v = "hello";//(定义并)初始化变量v

因为javascript为动态语言,其变量并没有固定的类型,其存储空间大小会随初始化与赋值而变化,所以其变量的“定义”就不像传统的静态语言一样了,其定义显得无关紧要。

声明提升

当前作用域内的声明都会提升到作用域的最前面,包括变量和函数的声明

1
2
3
4
5
6
(function(){
  var a = "1";
  var f = function(){};
  var b = "2";
  var c = "3";
})();

变量a,f,b,c的声明会被提升到函数作用域的最前面,类似如下:

1
2
3
4
5
6
7
(function(){
  var a,f,b,c;
  a = "1";
  f = function(){};
  b = "2";
  c = "3";
})();

请注意函数表达式并没有被提升,这也是函数表达式与函数声明的区别。进一步看二者的区别:

1
2
3
4
5
6
7
8
9
(function(){
  //var f1,function f2(){}; //hoisting,被隐式提升的声明
  f1(); //ReferenceError: f1 is not defined
  f2();
  var f1 = function(){};
  function f2(){}
})();

上面代码中函数声明f2被提升,所以在前面调用f2是没问题的。虽然变量f1也被提升,但f1提升后的值为undefined,其真正的初始值是在执行到函数表达式处被赋予的。所以只有声明是被提升的。

名字解析顺序

javascript中一个名字(name)以四种方式进入作用域(scope),其优先级顺序如下:

1、语言内置:所有的作用域中都有 this 和 arguments 关键字

2、形式参数:函数的参数在函数作用域中都是有效的

3、函数声明:形如function foo() {}

4、变量声明:形如var bar;

名字声明的优先级如上所示,也就是说如果一个变量的名字与函数的名字相同,那么函数的名字会覆盖变量的名字,无论其在代码中的顺序如何。但名字的初始化却是按其在代码中书写的顺序进行的,不受以上优先级的影响。看代码:

1
2
3
4
5
6
7
8
9
(function(){
    var foo;
    console.log(typeof foo); //function
     
    function foo(){}
    foo = "foo";
    console.log(typeof foo); //string
})();

如果形式参数中有多个同名变量,那么最后一个同名参数会覆盖其他同名参数,即使最后一个同名参数并没有定义。

以上的名字解析优先级存在例外,比如可以覆盖语言内置的名字arguments。

命名函数表达式

可以像函数声明一样为函数表达式指定一个名字,但这并不会使函数表达式成为函数声明。命名函数表达式的名字不会进入名字空间,也不会被提升。

1
2
3
4
5
f();//TypeError: f is not a function
foo();//ReferenceError: foo is not defined
var f = function foo(){console.log(typeof foo);};
f();//function
foo();//ReferenceError: foo is not defined

命名函数表达式的名字只在该函数的作用域内部有效。

===

在认识一切事物之后,人才能认识自己,因为事物仅仅是人的界限。 —— 尼采

 

Js作用域与作用域链详解

http://blog.csdn.net/yueguanghaidao/article/details/9568071

  一直对Js的作用域有点迷糊,今天偶然读到Javascript权威指南,立马被吸引住了,写的真不错。我看的是第六版本,相当的厚,大概1000多页,Js博大精深,要熟悉精通需要大毅力大功夫。

一:函数作用域

   先看一小段代码:

[javascript] view plaincopy
  1. var scope="global";  
  2. function t(){  
  3.     console.log(scope);  
  4.     var scope="local"  
  5.     console.log(scope);  
  6. }  
  7. t();  

(PS: console.log()是firebug提供的调试工具,很好用,有兴趣的童鞋可以用下,比浏览器+alert好用多了)

第一句输出的是: "undefined",而不是 "global"

第二讲输出的是:"local"

  你可能会认为第一句会输出:"global",因为代码还没执行var scope="local",所以肯定会输出“global"。

  我说这想法完全没错,只不过用错了对象。我们首先要区分Javascript的函数作用域与我们熟知的C/C++等的块级作用域。

  在C/C++中,花括号内中的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的。而Javascript压根没有块级作用域,而是函数作用域.

所谓函数作用域就是说:-》变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

所以根据函数作用域的意思,可以将上述代码重写如下:

[javascript] view plaincopy
  1. var scope="global";  
  2. function t(){  
  3.     var scope;  
  4.     console.log(scope);  
  5.     scope="local"  
  6.     console.log(scope);  
  7. }  
  8. t();  

    我们可以看到,由于函数作用域的特性,局部变量在整个函数体始终是由定义的,我们可以将变量声明”提前“到函数体顶部,同时变量初始化还在原来位置。

为什么说Js没有块级作用域呢,有以下代码为证:

[javascript] view plaincopy
  1. var name="global";  
  2. if(true){  
  3.     var name="local";  
  4.     console.log(name)  
  5. }  
  6. console.log(name);  

都输出是“local",如果有块级作用域,明显if语句将创建局部变量name,并不会修改全局name,可是没有这样,所以Js没有块级作用域。

现在很好理解为什么会得出那样的结果了。scope声明覆盖了全局的scope,但是还没有赋值,所以输出:”undefined“。

所以下面的代码也就很好理解了。

[javascript] view plaincopy
  1. function t(flag){  
  2.     if(flag){  
  3.         var s="ifscope";  
  4.         for(var i=0;i<2;i++)   
  5.             ;  
  6.     }  
  7.     console.log(i);  
  8.     console.log(s);  
  9. }  
  10. t(true);  

输出:2  ”ifscope"





二:变量作用域

还是首先看一段代码:

[javascript] view plaincopy
  1. function t(flag){  
  2.     if(flag){  
  3.         s="ifscope";  
  4.         for(var i=0;i<2;i++)   
  5.             ;  
  6.     }  
  7.     console.log(i);  
  8. }  
  9. t(true);  
  10. console.log(s);  



就是上面的翻版,知识将声明s中的var去掉。

程序会报错还是输出“ifscope"呢?

让我揭开谜底吧,会输出:”ifscope"

这主要是Js中没有用var声明的变量都是全局变量,而且是顶层对象的属性。

所以你用console.log(window.s)也是会输出“ifconfig"



当使用var声明一个变量时,创建的这个属性是不可配置的,也就是说无法通过delete运算符删除

var name=1    ->不可删除

sex=”girl“         ->可删除

this.age=22    ->可删除



三:作用域链

先来看一段代码:

[javascript] view plaincopy
  1. name="lwy";  
  2. function t(){  
  3.     var name="tlwy";  
  4.     function s(){  
  5.         var name="slwy";  
  6.         console.log(name);  
  7.     }  
  8.     function ss(){  
  9.         console.log(name);  
  10.     }  
  11.     s();  
  12.     ss();  
  13. }  
  14. t();  



当执行s时,将创建函数s的执行环境(调用对象),并将该对象置于链表开头,然后将函数t的调用对象链接在之后,最后是全局对象。然后从链表开头寻找变量name,很明显

name是"slwy"。

但执行ss()时,作用域链是: ss()->t()->window,所以name是”tlwy"

下面看一个很容易犯错的例子:

[html] view plaincopy
  1. <html>  
  2. <head>  
  3. <script type="text/javascript">  
  4. function buttonInit(){  
  5.     for(var i=1;i<4;i++){  
  6.         var b=document.getElementById("button"+i);  
  7.         b.addEventListener("click",function(){ alert("Button"+i);},false);  
  8.     }  
  9. }  
  10. window.οnlοad=buttonInit;  
  11. script>  
  12. head>  
  13. <body>  
  14. <button id="button1">Button1button>  
  15. <button id="button2">Button2button>  
  16. <button id="button3">Button3button>  
  17. body>  
  18. html>  

当文档加载完毕,给几个按钮注册点击事件,当我们点击按钮时,会弹出什么提示框呢?

很容易犯错,对是的,三个按钮都是弹出:"Button4",你答对了吗?

当注册事件结束后,i的值为4,当点击按钮时,事件函数即function(){ alert("Button"+i);}这个匿名函数中没有i,根据作用域链,所以到buttonInit函数中找,此时i的值为4,

所以弹出”button4“。



四:with语句

说到作用域链,不得不说with语句。with语句主要用来临时扩展作用域链,将语句中的对象添加到作用域的头部。

看下面代码

[javascript] view plaincopy
  1. person={name:"yhb",age:22,height:175,wife:{name:"lwy",age:21}};  
  2. with(person.wife){  
  3.     console.log(name);  
  4. }  

with语句将person.wife添加到当前作用域链的头部,所以输出的就是:“lwy".

with语句结束后,作用域链恢复正常。



 

转载于:https://www.cnblogs.com/silentjesse/p/4024536.html

更多相关:

  • 草色新雨中, 松声晚窗里。之前我们学习 Power Query 都是用鼠标就完成了很多复杂的操作。虽然 PowerQuery 已经将大部分常用功能内置成到功能区。基本能完成我们大部分的报表自动化功能。但是总有些复杂的或者个性化的问题是开发团队没有预先想到的,这时我们就需要学习 M 语言。一、M 语言在哪里?M语言的函数公式有三个地...

  • 前言从2020年3月份开始,计划写一系列文档--《小白从零开始学编程》,记录自己从0开始学习的一些东西。第一个系列:python,计划从安装、环境搭建、基本语法、到利用Django和Flask两个当前最热的web框架完成一个小的项目第二个系列:可能会选择Go语言,也可能会选择Vue.js。具体情况待定,拭目以待吧。。。基本概念表达式表...

  • 1.1函数1.1.1什么是函数函数就是程序实现模块化的基本单元,一般实现某一功能的集合。函数名:就相当于是程序代码集合的名称参数:就是函数运算时需要参与运算的值被称作为参数函数体:程序的某个功能,进行一系列的逻辑运算return 返回值:函数的返回值能表示函数的运行结果或运行状态。1.1.2函数的作用函数是组织好的,可重复使用的,用来...

  • 原标题:基于Python建立深度神经网络!你学会了嘛?图1 神经网络构造的例子(符号说明:上标[l]表示与第l层;上标(i)表示第i个例子;下标i表示矢量第i项)单层神经网络图2 单层神经网络示例神经元模型是先计算一个线性函数(z=Wx+b),接着再计算一个激活函数。一般来说,神经元模型的输出值是a=g(Wx+b),其中g是激活函数(...

  • 在学习MySQL的时候你会发现,它有非常多的函数,在学习的时候没有侧重。小编刚开始学习的时候也会有这个感觉。不过,经过一段时间的学习之后,小编发现尽管函数有很多,但是常用的却只有那几个。今天小编就把常用的函数汇总一下,为大家能够能好的学习MySQL中的函数。MySQL常使用的函数大概有四类。时间函数、数学函数、字符函数、控制函数。让我...

  • javascript的作用域是一个老生常谈的问题了。高程啊,或是各种书籍上都有关于javascript的作用域的阐述。这一次看了,《你不知道的JavaScript》里关于作用域的描述,感觉挺不错的。 编译 JavaScript是脚本语言,解释型语言,很多人可能认为它要跟其他的编译型语言划分界限,毫不相干。但是JavaScript确实是...

  • JavaScript采用的是词法作用域 1.词法作用域 即函数定义时,即确定的作用域。js中的作用域链,在函数声明时候,就已经确定了,无论函数在何处调用,其作用域变量的查找都是按照定义是包含关系去查找。 2.动态作用域 变量的作用域与函数的调用地点有关,在不同的函数中调用,变量的查找会沿着调用函数向上查找。 举例: var a =...

  • //获取某一个cookie的值 const getCookie = key => {var k = key, dc = document.cookie;if (dc.length > 0) {var s = dc.indexOf(k + "=");if (s != -1) {s = s + k.length + 1;var e = d...

  • var SGheadMapPoints = {/*obj={ maxLng: minLng: maxLat: minLat: maxCount:最大人数 minCount:最小人数 total:点位数量 }*/get: function (obj) {var arr = [];obj.maxCount || (obj.maxCount...

  • //自动搜索指定的请柬 var alertTipText = "请柬找到了,就在这个网页里面,自己仔细看吧"; var delay = 1 * 1000;//1秒后循环下一页寻找 /*获取子DOM元素在父元素里面的索引位置(是第几个元素)*/ function getNodeListIndex(childNode) {return c...

  •  获取天气情况(不支持跨域) /*json原生获取*/ function getJSON() {var XML;var url = "http://wthrcdn.etouch.cn/weather_mini?city=杭州";if (window.XMLHttpRequest) {XML = new XMLHttpRequest(...