一:作用域

  说起变量第一个要说到的肯定就是作用域,正是因为不熟悉JS的 作用域,往往就会把面向对象的作用域张冠李戴,毕竟有些东西总是习惯性的这样,但是并不是每次照搬都是可以的,那么下一个问题就来了,js到底是什么作用域,当然是函数作用域了,我们的浏览器就是一个被实例化的window对象,如果在window下定义一个name字段,那么name字段就具有window这个函数作用域,也就是在window下都是可以访问的,如果在window下定义一个function print,然后里面再定义一个name,那么这个新定义的name只能在print函数下通用,而老的name继续在window下通用,举个例子。

var name = "name1";
function print(){
var name = "name2";
console.log(name);
}
print();
console.log(name);

从图中可以看出两点:

1: 在window下定义了一个name,居然还可以在function下定义一个重名的name,这个在C#里面是不可想象的。

2:在JS下,它只认自己的作用域,所以就出现了第一个"liu",你可能觉得这个没有什么稀奇的地方,这是因为可能你还没有真正理解什么是函数作用域,解析器在执行print的时候,第一件事情就是寻找print下的所有局部变量,然后再执行后续语句,既然是先寻找,那么var name="print"这条语句定义在ctrip中任何位置都是可以的,下面我们把语句调换过来。

var name = "name1";
function print(){ console.log(name);
var name = "name2";
}
print();
console.log(name);

可以看到在print函数下,第一个console.log输出的是undefined,这个结果可以证实,确实做了第一件事情是收集到了name这个局部变量,可能有人说为什么没有变成" liu ",那是因为初始化操作必须是逐语句执行,所以在ctrip函数中执行console.log(name)时,此时解析器只知道有一个未赋值的变量name,所以就console的时候就是undefined了。

二:作用域链

   从上面的例子中我们也很清楚的知道了,在function中定义的变量只具有function范围内的作用域,同时我们也看到上面这个例子只是一层嵌套,window是个大的function,里面是一个print的function,同样的道理也可以延伸到多层嵌套,比如三层,四层。。。。N层,这些层就形成了一个链式结构。

var name = "name1";
function print(){
var name = "name2";
console.log(name);
function newprint(){
var name = "name3";
console.log(name);
}
newprint();
}
print();
console.log(name);

从图中可以看到,我在print下再定义了一个newprint函数,这样的话就有三层了,输出的结果也是我们希望看到的,每层的name只在自己的作用域范围内生效,但是下面有一个问题来了,有时,在定义newprint的函数时,把 var name="name3" 中的var忘记写了,那么这个时候,newprint中的name到底是什么值呢? 是first还是second呢?

var name = "name1";
function print(){
var name = "name2";
console.log(name);
function newprint(){
name = "name3";
console.log(name);
}
newprint();
}
print();
console.log(name);

仔细想想会发现,当代码执行到newprint函数中的name="name3"时,发现newprint函数中并没有name这个局部变量,恰好代码又在print这个大函数中,所以解析器就会回溯到print函数中寻找name,发现果然有name,这个时候就把print的name修改成了" name3"。

另外一种情况,在定义newprint函数的时候,不小心把name="name3" 错写成了 nam="name3"; 丢了一个e,又不是我代码的问题。那么这个时候解析器该怎么处理?同样的道理,在回溯时,发现print没有,再回溯到顶层的window下,发现还是没有,这个时候解析器做了这样的处理,既然整个链中都没有,你又赋值了,我总不能给你报错,那多尴尬呀,就索性给你在window下隐式的定义一个nam变量,这个时候nam其实就是全局变量了。我们可以在window顶层console一下nam看看。

var name = "name1";
function print(){
var name = "name2";
console.log(name);
function newprint(){
nam = "name3";
console.log(name);
}
newprint();
}
print();
console.log(name);
console.log(nam);

JavaScript 之 变量的更多相关文章

  1. javascript中变量提升的理解

    网上找了两个经典的例子 var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); // 10 var ...

  2. javascript的变量作用域--对比js、php和c的for循环

    为什么要写这篇文章呢?主要是给自己提个醒,js的水很深,需要小心点儿才能趟过去,更何况自己不是专业人士,那就得更加小心了. 看下面的js代码: <!DOCTYPE html> <ht ...

  3. [转]深入理解JavaScript的变量作用域

    1.JavaScript的作用域链 2.函数体内部,局部变量的优先级比同名的全局变量高. 3.JavaScript没有块级作用域. 4.函数中声明的变量在整个函数中都有定义. 5.未使用var关键字定 ...

  4. JavaScript笔记:变量及其作用域

    一.变量的定义及声明 在javascript中变量仅仅是用来保存值的一个占位符而已,定义变量时要使用关键字var后跟一个变量名,如下所示: var message; //定义一个变量message,像 ...

  5. JavaScript中变量提升是语言设计缺陷

    首先纠正下,文章标题里的 “变量提升” 名词是随大流叫法,“变量提升” 改为 “标识符提升” 更准确.因为变量一般指使用 var 声明的标识符,JS 里使用 function 声明的标识符也存在提升( ...

  6. JavaScript中变量和函数声明的提升

    现象: 1.在JavaScript中变量和函数的声明会提升到最顶部执行. 2.函数的提升高于变量的提升. 3.函数内部如果用var声明了相同名称的外部变量,函数将不再向上寻找. 4.匿名函数不会提升. ...

  7. JavaScript 中变量、作用域和内存问题的学习

    这是我学习JavaScript的第二篇文章,之前做过几年的Java开发,发现JavaScript虽然也是面向对象的语言但是确实有很多不同之处.就本篇博客,主要学习总结一下最近学习到的JavaScrip ...

  8. Javascript的变量与delete操作符

    原文:http://charlee.li/javascript-variables-and-delete-operator.html 刚刚看到一篇好文(原文链接), 对Javascript中的dele ...

  9. 深入理解JavaScript的变量作用域(转载Rain Man之作)

    在学习JavaScript的变量作用域之前,我们应当明确几点: JavaScript的变量作用域是基于其特有的作用域链的. JavaScript没有块级作用域. 函数中声明的变量在整个函数中都有定义. ...

  10. javascript之变量、作用域、作用域链

    一.变量 javascript的变量是松散类型的,所谓松散类型就是说定义的变量可以用来保存任何类型的数据.定义变量时要使用var操作符后面跟变量名.这里的var是一个关键字,如果定义变量时省略了var ...

随机推荐

  1. Date与String间的转换

    一.Date-->String :格式化过程 1. DateFormat :String format(Date d) 2.SimpleDateFormat是继承DateFormat(抽象类)的 ...

  2. [MySql]锁表与解锁

    摘要 为啥会出现锁表的情况?锁表会导致数据表的其他操作超时,频繁的插入修改查询很容易出现锁表的情况.如果遇到这种情况,临时的解决办法,可以通过下面的方式进行解锁.如果长期有效的解决,那么就需要优化项目 ...

  3. spring boot JedisCluster连接redis集群配置

    配置文件 配置类 构造的时候, 可以看一下, 只有Set<HostAndPort> 参数是必须的 做了一层封装, 更方便使用 结果

  4. 无法完成你的itunes store 请求发生未知错误50

    装上itunes登陆itunes store时遂发现"无法完成您的itunes store的请求,发生未知错误(-50)"跃入眼帘,卸载重装数次还是不见效果,难道是WIN7和itu ...

  5. Spring事务传播机制与隔离级别(转)

    Spring事务传播机制与隔离级别 博客分类: Spring   转自:http://blog.csdn.net/edward0830ly/article/details/7569954 (写的不错) ...

  6. 自定义圆形控件RoundImageView并认识一下attr

    昨天我们学习了自定义带图片和文字的ImageTextButton,非常简单,我承诺给大家要讲一下用自定义属性的方式学习真正的实现自定义控件,在布局文件中使用属性的方式就需要用到attr.xml这个文件 ...

  7. 修改Eclipse/MyEclipse项目的默认编码

    应该是中文操作系统的原因,eclipse默认的新项目的编码是GBK,出于对编码支持的考虑,项目组中最好统一要求是UTF-8编码进行开发. 修改eclipse的配置,可以使得eclipse的新建项目的默 ...

  8. vc 获得调用者的模块名称

    void ShowCallerModuleName(void* calleraddr ){ HMODULE hCallerModule = NULL; TCHAR szModuleName[MAX_P ...

  9. redis.clients.jedis.exceptions.JedisDataException: WRONGTYPE Operation against a key holding the wrong kind of value

    错误原因: 因为redis中已经存在了相同的key, 而且key对应的值类型并不是Set,而是SortSet(改动前):再调用smembers时,抛出此错误. 解决方法: 将原来的的key给Del掉, ...

  10. 怎样在centos安装python-mysql?

    在python中使用mysql,须要安装mysql-python依赖包, 能够通过pip来安装: pip install MySQL-python 假设错误发生,须要先安装一个开发包: yum ins ...