JS的作用域和声明提前

首先介绍下Javascript的函数作用域的概念,然后了解下什么是作用域和声明提前,最后通过一个例子剖析Javascript的作用域链。

1.变量的作用域

稍微有些编程背景的都知道,变量的作用域分为两种: 全局变量 和 局部变量 。

Javascript是一门 弱类型语言 。所有的变量声明都是通过var来接收,如

  1. var num = 1;
  2. var str = “string”;
  3. var flag = true;

看似是一个非常省事的机制,但是也有让人头疼的时候,一些隐式的类型转换经常会把搞晕。先看看全局变量和局部变量:

  1. var g = "global"; function f(){ var l = "local";
  2. }

注意 : 1. 如果在函数f()中将去掉var声明,则变量l就会从局部变量升级为全局变量。

2. 局部变量的优先级高于同名的全局变量 。如果在函数f()中声明一个局部变量也为g,则全局变量就会被局部变量覆盖

2.作用域和声明提前

看到Javascript作用域这块,可以说颠覆了以前我对作用域的认识。类似Java和C等编程语言,在花括号“{}”内的代码都是有各自的作用域的,并且在这个范围以外,这些变量是不可见的,我们称这种作用域为 块级作用域 。

但是这完全不适用于Javascript,因为Javascript没有块级作用域,但是Javascript有 函数作用域 。函数作用域简言之就是:变量在声明他们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

对于“ 变量在声明他们的函数体以及这个函数体嵌套的任意函数体内都是有定义的 ”这句话的延伸理解:变量在声明之前就已经可用。我们称这种特性为声明提前,也就是函数里的所有变量都被“提前”至函数体的顶部。

下面我们看一个经典的陷阱案例:

  1. var v = "yoyo"; (function(){ console.log(v); var v = "check now";
  2. console.log(v);
  3. })();

对于第二次执行结果“check now”没有什么特别的,为什么第一次输出的不是“yoyo”而是“undefined”。

对于这个问题的解释就用到上面的那句话, 局部变量在整个函数体始终是有定义的 ,即在函数体内局部变量覆盖了同名全局变量,而且,程序只有在执行到var语句时,局部变量才会被真正赋值。所以,这时你大概会明白为什么是undefined了,因为此时还没有遇到var,即没有定义,等价于下面的形式:

  1. var v = "yoyo"; (function(){ var scope; console.log(v); var v = "check now";
  2. console.log(v);
  3. })();
  4. 疑问 ? ? ?
  5. 将上面的代码稍稍修改为:
  6. var v = "yoyo"; (function(){
  7. console.log(v);
  8. })();

运行结果为:

相比于上面的代码只是少了一行添加一个局部变量v并赋值的语句,但是结果却是“yoyo”。

这里之所以输出“yoyo”,不能按照上面的定式思维。上面有句话叫“局部变量在整个函数体始终是有定义的”,但是这里没有局部变量的定义,所以按照下面要提到的作用域链会逐层向上寻找变量,最后找到了全局变量v,从而最后的输出是“yoyo”。

举一个通俗点的例子,你准备要花钱买点东西时,会先摸摸自己的钱包,没了你可以找你爸要,你爸也没有就再找你爷爷,... 。而你爸没钱买东西时,他并不会来找你要。

以上是我的个人理解,如果你对这两种情况有自己的理解,请在下方给出,望不吝指教。

3.作用域链

全局变量在程序中始终是有定义的,局部变量在声明它的函数体内以及其所嵌套的函数内始终是有定义的。

每一段Javascript代码(全局代码或函数)都有一个与之相关联的作用域链,这个作用域链就是一个对象列表或链表。比如当 Javascript需要查找变量x的值时,它会从链中的第一个对象开始,如果该对象有一个名为x的属性,则直接使用,如果不存在名为x的属性,则会继续 向链上的下一个对象查找,如此递归下去直到找到。如果整个链上都找不到,则认为不存在x这个属性。举例:

  1. name="lwy"; function t(){ var name="tlwy"; function s(){ var name="slwy"; console.log(name); } function ss(){ console.log(name); } s();   ss();
  2. }
  3. t();

时间: 2024-12-30 00:01:31

JS的作用域和声明提前的相关文章

初探JavaScript(四)——JS另类的作用域和声明提前

前言:最近恰逢毕业季,千千万万的学生党开始步入社会,告别象牙塔似的学校生活.往往在人生的各个拐点的时候,情感丰富,感触颇深,各种对过去的美好的总结,对未来的展望.与此同时,也让诸多的老“园”工看完这些小年轻的文章后感触良多,不禁也要写上几笔,所以就出来了很多类似“毕业两年小记”.“毕业五年有感”…… 可能就是某篇博文的一句话,某碗心灵鸡汤就拨动了你心里的那根尘封已久的弦,让你情不自禁的点了个赞,还忍不住的要在下面评论区留下自己此刻心潮澎湃的印记. 我今天不是来送鸡汤的,鸡汤虽好,可不要贪杯哦.

【翻译】JavaScript中的作用域和声明提前

原文:http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html ===翻译开始=== 你知道下面的JavaScript脚本执行结果是什么吗? 1 var foo=1; 2 function bar(){ 3 if(!foo){ 4 var foo=10; 5 } 6 alert(foo); 7 } 8 bar(); 如果你对弹出的结果是"10"感到惊讶的话,那么下面这段脚本会让你晕头转向的: 1 var a=1

javascript的函数作用域及声明提前

废话不说:先来段代码: var scope='global';function test(){    alert(scope);        // 输出undefine:而不是global    var scope='local';      alert(scope);        // 输出local}test(); 脑算下:你可能会认为第一alert会输出global: 但是事实上第一个alert输出的是undefined: 这是怎么回事呢? 要探讨这个问题首先要解释下两个概念: 1:函

javascript中函数作用域和声明提前

javascript不像java等其他强类型语句,没有块级作用域(括号内的代码都有自己的作用域,变量在声明它们的代码段之外不可见)一说,但有自己的独特地方,即函数作用域. 函数作用域:变量在声明它们的函数体内以及这个函数体的任意内部函数体内是有定义的. 如下所示代码,在不同位置定义了变量i.j和k,它们都在同一个作用域内,即在函数体内均是有定义的. function test(){ var i=0; //i在整个函数体内均有定义 if(true){ var j=0; //j在整个函数体内均有定义

函数作用域和声明提前

JavaScript的函数作用域是指在函数内声明的所有变量在函数体内始终是可见的. 这意味着变量在声明之前已经可用.该特性被非正式地称为声明提前,即函数里声明的变量(不涉及赋值),都被提前到函数体的顶部 var scope = "global"; function f () { console.log(scope);//输出undefined,而不是"global" var scope = "local";//变量在这里赋初始值,但该变量在函数体

JAVASCRIPPT作用域-函数作用域和声明提前【摘自《Javascript 权威指南》】

一个变量的作用域是程序源代码中定义这个变量的区域.全局变量拥有全局作用域,在JavaScript代码中的任何地方都是有定义的. 然而在函数内声明的变量只在函数体内有定义.他们是局部变量,作用域是局部性的.函数参数也是局部变量,他们只在体内有定义. 在函数体内,局部变量的优先级高于同名的全局变量.如果在函数内声明的一个局部变量或函数参数中带有的变量和全局变量重名, 全局就被局部变量所覆盖. eg: var a="aaaa"; (function (){          var a=&q

前端面试题总结一(js变量和函数声明提前相关)

好久没有更新博客了,^_^写写博客吧!下面是我总结的一些面试题,希望对大家有所帮助 (1)题目如下: alert(a)  var a=1  function a(){    alert(a) } 好多人肯定会觉得输出的结果是undefined,那你就错了,因为function也要声明提前的所以输出的结果应该是:: ? a(){alert(a)} 更有意思的来了如果我把上面的题改为如下: alert(a)function a(){ alert(a)}var a=1 输出的结果应该是:: ? a()

浅谈js中函数作用域和声明提前

JavaScript的函数具有两个主要特性,一是函数是一个对象,二是函数提供作用域支持,今天主要聊聊函数的作用域支持. 简单看两个概念: 具名函数表达式 var add = function add (a) { return a } 这段代码描述了一个函数,称为‘具名函数表达式’. 如果省略函数表达式中的名字,它就是‘匿名函数表达式’,即匿名函数,例如 var add = function (a, b) { return a + b; }; 最后看下‘函数声明’ function foo() {

js(javascript)小谈变量声明(显隐声明,声明提前)

var a=5: function fun(){     a=0;              alert(a);         //0     alert(this.a);    //5     var a;      alert (a);        //0      } fun(); 以上代码  将会输出  0 ,5,0.首先在js中我们的变量声明赋值分为两个部分 .1.变量的声明 var a:2.变量的赋值 a=2;但是一般我们会把变量的声明和赋值写在 一起 也就是  var a=2: