[Effective JavaScript 笔记] 第12条:理解变量声明提升

js支持词法作用域,即除了极少的例外,对变量的引用会被绑定到声明变量最近的作用域中。

js不支持块级作用域,即变量定义的作用域并不是离其最近的封闭语句或代码块,而是包含它们的函数。

不了解这个会产生一些微妙的bug。

functon isWinner(palyer,others){

          var highest=0;

         for(var i=0,n=others.length;i<n;i++){

                   var palyer=others[i];

                  if(player.score>highest){

                           highest=player.score;

                  }

        }

         return player.score>highest;

}

  

这里的for循环里声明了一个局部变量player,但由于js中变量是函数级作用域,而不是块级作用域,所以在内部声明的player变量只是简单地重声明了一个已经存在于作用域内的变量(参数player)

该循环每次迭代都会重写同一变量。因此return 语句将player看作others的最后一个元素,而不是此函数的参数player。

理解js变量声明行为的一个好方法,是把变量声明看作两个过程,一个是声明过程,一个是赋值过程

js隐式提升的是声明部分到封闭函数的顶部,而将赋值留在原地。所以上面的函数相当于。

functon isWinner(palyer,others){

          var highest=0;

          var palyer;

         for(var i=0,n=others.length;i<n;i++){

                palyer=others[i];

                if(player.score>highest){

                     highest=player.score;

                 }

         }

        return player.score>highest;

}

  

在同一函数中多次声明相同变量是合法的。变量声明提升也可能导致变量重声明的混淆。

function trimSections(header,body,footer){

       for(var i=0,n=header.length;i<n;i++){

                   header[i]=header[i].trim();

       }

      for(var i=0,n=body.length;i<n;i++){

           body[i]=body[i].trim();

       }

      for(var i=0,n=footer.length;i<n;i++){

                footer[i]=footer[i].trim();

      }

}

  

经过变量提升后相当于

for(i=0,n=body.length;i<n;i++){

       body[i]=body[i].trim();

}

for(i=0,n=footer.length;i<n;i++){

       footer[i]=footer[i].trim();

}

  

因为重声明会导致截然不同的变量展现,一些程序员喜欢通过有效地手动提升变量将所有的var声明放置在函数的顶部,从而避免歧义。

重要的是,不管是写代码还是读代码,都要理解js的作用域规则

js 没有块级作用域的一个例外好处是其异常处理。

try…catch语句将捕获的异常绑定到一个变量,该变量的作用域只是catch块。

function test(){

        var x=”var”,res=[];

        res.push(x);

        try{

               throw “exception”;

        }catch(x){

            x=”catch”;

       }

       res.push(x);

       return res;

}

test();//[”var ”,”var ”]

  

提示

  • 在代码块中的变量声明会被隐式地提升到封闭函数的顶部
  • 重声明变量被视为单个变量
  • 考虑手动提升局部变量的声明,从而避免混淆
时间: 2024-12-23 07:33:21

[Effective JavaScript 笔记] 第12条:理解变量声明提升的相关文章

[Effective JavaScript 笔记] 第9条:始终声明局部变量

如果忘记将变量声明为局部变量,该变量将会隐式地转变为全局变量 function swap(a,i,j){ temp=a[i]; a[i]=a[j]; a[j]=temp; } 尽管该程序没有使用var声明temp变量,执行不会出错,而且temp会被添加到全局使用域中,变成一个全局变量. 修正过的代码 function swap(a,i,j){ var temp=a[i]; a[i]=a[j]; a[j]=temp; } 故意创建全局变量是不好的风格,意外创建是一种灾难. 可以使用lint工具对代

[Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+1}" 反射获取函数源代码的功能很强大,使用函数对象的toString方法有严重的局限性.toString方法的局限性ECMAScript标准对函数对象的toString方法的返回结果(即该字符串)并没有任何要求.这意味着不同的js引擎将产生不同的字符串,甚至产生的字符串与该函数并不相关. 如果函数

[Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式传递给eval函数以达到同样的功能.程序员面临一个选择:应该将代码表示为函数还是字符串?毫无疑问,应该将代码表示为函数.字符串表示代码不够灵活的一个重要原因是:它们不是闭包. 闭包回顾 看下面这个图 js的函数值包含了比调用它们时执行所需要的代码还要多的信息.而且js函数值还在内部存储它们可能会引用

[Effective JavaScript 笔记]第2章:变量作用域--个人总结

前言 第二章主要讲解各种变量作用域,通过这章的学习,接触到了很多之前没有接触过的东西,比如不经常用到的eval,命名函数表达式,with语句块等,下面是一个列表,我对各节的一点点个人总结,很多都是自己的收获和认识.可能有很多认识的误区,毕竟水平有限.如果有那里认识不对的地方,还希望可以在评论中指出来,这样可以得到大家在学习的帮助,也是很不错的. 第8条:尽量少用全局对象 个人总结: 解释全局对象在JS中定义的随意性,导致所有人都可以去定义去修改,导致命名冲突.对这样的全局对象进行依赖,导致不可知

[Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //"number" typeof "s";//"string" typeof null;//"object":ECMAScript把null描述为独特的类型,但返回值却是对象类型,有点困惑. 可以使用Object.prototype.t

深入理解变量声明提升和函数声明提升

变量声明提升 1.变量定义 可以使用var定义变量,变量如果没有赋值,那变量的初始值为undefined. 2.变量作用域 变量作用域指变量起作用的范围.变量分为全局变量和局部变量.全局变量在全局都拥有定义:而局部变量只能在函数内有效. 在函数体内,同名的局部变量或者参数的优先级会高于全局变量.也就是说,如果函数内存在和全局变量同名的局部变量或者参数,那么全局变量将会被局部变量覆盖. 所有不使用var定义的变量都视为全局变量 3.函数作用域和声明提前 JavaScript的函数作用是指在函数内声

关于Javascript没有块级作用域和变量声明提升

Javascript是没有块级作用域的,在语句块中声明的变量将成为语句块所在代码片段的局部变量.例如: 1 if(true){ 2 var x=3; 3 } 4 console.log(x); 结果输出3. 再如: 1 var x=5; 2 3 function a(){ 4 if(!x){ 5 var x=10; 6 } 7 console.log(x); 8 } 9 a(); 结果是10.因为变量声明的提升,原理是这样的,举个例子: 1 if(a==undefined){ 2 alert("

[Effective JavaScript 笔记]第30条:理解prototype、getPrototypeOf和__ptoto__之间的不同

原型包括三个独立但相关的访问器.这三个单词都是对单词prototype做了一些变化. C.prototype用于建立由new C()创建的对象的原型 Object.getPrototypeOf(obj)是ES5中用来获取obj对象的原型对象的标准方法 obj.__proto__是获取obj对象的原型对象的非标准方法 一个例子 要理解这些访问器,我们拿一个典型的js数据类型作例子.假设User构造函数需要通过new操作符来调用.它需要两个参数,即姓名和密码的哈希值,并将它们存储在创建的对象中.代码

[Effective JavaScript 笔记]第24条:使用变量保存arguments对象

迭代器(iterator)是一个可以顺序存取数据集合的对象.其一个典型的API是next方法.该方法获得序列中的下一个值. 迭代器示例 题目:希望编写一个便利的函数,它可以接收任意数量的参数,并为这些值建立一个迭代器. 测试代码好下: var it=values(1,4,1,4,2,1,3,5,6); it.next();//1 it.next();//4 it.next();//1 分析:由于values函数需要接收任意多个参数,这里就需要用到上一节讲到的构建可变参数的函数的方法.然后里面的迭