java语言里有一句很经典的话:java的世界里,一切皆是对象

Javascript虽然跟java没有半点毛关系,但是很多会使用javascript的朋友同样认为:javascript的世界里,一切也皆是对象

  其实javascript语言和java语言一样变量是分为两种类型:基本数据类型和引用类型。

  基本类型是指:Undefined、Null、Boolean、Number和String;而引用类型是指多个指构成的对象,所以javascript的对象指的是引用类型。在java里能说一切是对象,是因为java语言里对所有基本类型都做了对象封装,而这点在javascript语言里也是一样的,所以提在javascript世界里一切皆为对象也不为过。

Javascript里的基本变量是存放在栈区的(栈区指内存里的栈内存),它的存储结构如下图所示:


   javascript里引用变量的存储就比基本类型存储要复杂多,引用类型的存储需要内存的栈区和堆区(堆区是指内存里的堆内存)共同完成,如下图所示:

  在javascript里变量的存储包含三个部分:

    部分一:栈区的变量标示符;

    部分二:栈区变量的值;

    部分三:堆区存储的对象。

JS中变量赋值和函数传参都是传递栈区的值。JS中的变量未定义不能访问,但可以不用var定义而直接出现在赋值语句中,此时相当于在全局通过var定义该变量,实际上是window的一个属性。

 其实javascript里的变量和其他语言有很大的不同,javascript的变量是一个松散的类型,松散类型变量的特点是变量定义时候不需要指定变量的类型,变量在运行时候可以随便改变数据的类型,但是这种特性并不代表javascript变量没有类型,当变量类型被确定后javascript的变量也是有类型的。但是在现实中,很多程序员把javascript松散类型理解为了javascript变量是可以随意定义即你可以不用var定义,也可以使用var定义,其实在javascript语言里变量定义没有使用var,变量必须有赋值操作,只有赋值操作的变量是赋予给window,这其实是javascript语言设计者提升javascript安全性的一个做法。

  此外javascript语言的松散类型的特点以及运行时候随时更改变量类型的特点,很多程序员会认为javascript变量的定义是在运行期进行的,更有甚者有些人认为javascript代码只有运行期,其实这种理解是错误的,javascript代码在运行前还有一个过程就是:预加载,预加载的目的是要事先构造运行环境例如全局环境,函数运行环境,还要构造作用域链,而环境和作用域的构造的核心内容就是指定好变量属于哪个范畴,因此在javascript语言里变量的定义是在预加载完成而非在运行时期。

var ooo = null;

    console.log(ooo);// 运行结果:null

    console.log(ooo == undefined);// 运行结果:true

    console.log(ooo == null);// 运行结果:true

    console.log(ooo === undefined);// 运行结果:false

    console.log(ooo === null);// 运行结果:true

  运行之,结果很震惊啊,null居然可以和undefined相等,但是使用更加精确的三等号“===”,发现二者还是有点不同,其实javascript里undefined类型源自于null即null是undefined的父类,本质上null和undefined除了名字这个马甲不同,其他都是一样的,不过要让一个变量是null时候必须使用等号“=”进行赋值了。

  当变量为undefined和null时候我们如果滥用它javascript语言可能就会报错,后续代码会无法正常运行,所以javascript开发规范里要求变量定义时候最好马上赋值,赋值好处就是我们后面不管怎么使用该变量,程序都很难因为变量未定义而报错从而终止程序的运行,例如上文里就算变量是string基本类型,在变量定义属性程序还是不会报错,这是提升程序健壮性的一个重要手段,由引子的例子我们还知道,变量定义最好放在变量所述作用域的最前端,这么做也是保证代码健壮性的一个重要手段。

函数传递参数的本质就是外部的变量复制到函数参数的变量里,我们看看下面的代码:

    function testFtn(sNm,pObj){

        console.log(sNm);// 运行结果:new Name

        console.log(pObj.oName);// 运行结果:new obj

        sNm = "change name";

        pObj.oName = "change obj";

    }

    var sNm = "new Name";

    var pObj = {oName:"new obj"};

    testFtn(sNm,pObj);

    console.log(sNm);// 运行结果:new Name

    console.log(pObj.oName);// 运行结果:change obj
 var ftn1 = function(){

        console.log("test:ftn1");

    };

    var ftn2 = function(){

        console.log("test:ftn2");

    };

    function ftn(f){

       f();

       f = ftn2;

    }

    ftn(ftn1);// 运行结果:test:ftn1

    console.log("====================华丽的分割线======================");

    ftn1();// 运行结果:test:ftn1

  这个代码是很早之前有位朋友考我的,我当时答对了,但是我是蒙的,问我的朋友答错了,其实当时我们两个都没搞懂其中缘由,我朋友是这么分析的他认为f是函数的参数,属于函数的局部作用域,因此更改f的值,是没法改变ftn1的值,因为到了外部作用域f就失效了,但是这种解释很难说明我上文里给出的函数传参的实例,其实这个问题答案就是函数传参的原理,只不过这里加入了个混淆因素函数,在javascript函数也是对象,局部作用域里f = ftn2操作是将f在栈区的地址改为了ftn2的地址,对外部的ftn1和ftn2没有任何改变。

  记住:javascript里变量复制和函数传参都是在传递栈区的值

  栈区的值除了变量复制起作用,它在if语句里也会起到作用,当栈区的值为undefined、null、“”(空字符串)、0、false时候,if的条件判断则是为false,我们可以通过!运算符计算,因此当我们的代码如下:

    var obj = {};

    if (!!obj){

        console.log("true");

    }else{

        console.log("false");

    }

  结果则是true,因为var obj = {}相当于var obj = new Object(),虽然对象里没什么内容,但是在堆区里,对象的内存已经分配了,而变量栈区的值已经是内存地址了,所以if语句判断就是true了。

谈谈javascript语法里一些难点问题(一)

2015第35周五JavaScript变量的更多相关文章

  1. 2015第37周五javascript函数arguments对象巧用一

    Javascript函数的一个巧妙利用:假定action中有一个JSONObject类型的对象data,其值有可能为空,则前台JSP页面的JS代码中想直接通过EL表达式,即${data}的形式访问对象 ...

  2. 【规范】javascript 变量命名规则

    javascript 有三大经典的变量命名法:匈牙利命名法,驼峰式命名法和帕斯卡命名法.今天主要介绍下这三种命名方式. 匈牙利命名法 语法 变量名 = 类型 + 对象描述 类型指变量的类型 对象描述指 ...

  3. 【规范】javascript 变量命名规则(转)

    匈牙利命名法 语法 变量名 = 类型 + 对象描述 类型指变量的类型 对象描述指对象名字全称或名字的一部分,要求有明确含义,命名要容易记忆容易理解. 通过在变量名前面添加相应小写字母的符号标示作为前缀 ...

  4. javascript变量的作用域

    javascript变量的作用域 基本类型和引用类型 基本类型值指的是简单的数据段,而引用类型值指的是那个可能由多个值组成的对象  讲一个值赋值给变量时,javascript解析器首先要确定是基本类型 ...

  5. JavaScript 变量声明提前

    <JavaScript权威指南>中指出:JavaScript变量在声明之前已经可用,JavaScript的这个特性被非正式的称为声明提前(hoisting),即JavaScript函数中声 ...

  6. JavaScript 变量

    一,JavaScript 变量(存储信息的容器) 与代数一样,JavaScript 变量可用于存放值(比如 x=2)和表达式(比如 z=x+y). 变量可以使用短名称(比如 x 和 y),也可以使用描 ...

  7. javascript变量声明 及作用域

    javascript变量声明提升(hoisting) http://openwares.net/js/javascript_declaration_hoisting.html 可能要FQ一下 java ...

  8. JavaScript 变量作用域

    一. 变量声明 变量用var关键字来声明,如下所示: 变量在未声明的情况下被初始化,会被添加到全局环境. JavaScript执行代码时,会创建一个上下文执行环境,全局环境是最外围的环境.每个函数在被 ...

  9. 【转】javascript变量声明 及作用域

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

随机推荐

  1. Windows与Linux文件共享

    Windows与Linux文件共享 Samba服务器 安装Samba服务器 rpm –ivh /mnt/Packages/Samba-3.5.10-125.el6.i686.rpm 添加用户并修改密码 ...

  2. jquery $('#btn').click与$("#btn").live("click",function()有什么区别?

    live方法绑定的事件处理函数,在页面中未来添加的元素只要满足原来的选择器,仍然会导致事件触发.普通的事件绑定则没有这个效果.对于#btn这个选择器来说,如果你未来将id为btn的元素删除,然后再创建 ...

  3. window.applicationCache事件,介绍

    1.关于applicationCache对象 在IE和Google中 为ApplicationCache对象 而在FF中为 OfflineResourceList对象 通过ApplicationCac ...

  4. (转)Mac OS X中配置Apache

    我使用的Mac OS X版本是10.8.2,Mac自带了Apache环境. 启动Apache 设置虚拟主机 启动Apache 打开“终端(terminal)”,输入 sudo apachectl -v ...

  5. Objective-C学习篇02—封装

    面向对象的三大特性:封装.继承和多态 封装目的就是将数据隐藏起来,外界只能通过这个类的方法(接口)才能访问或者设置里面的数据,不可以在外部直接修改或者访问里面的数据,通常使用方法来达到封装一个类的目的 ...

  6. Linux挂载U盘

    在将硬盘插到Linux系统上,打开硬盘时一直提示:unknown filesystem type 'ntfs'. 1.安装gcc,提供编辑环境 yum -y install gcc 2.下载ntfs- ...

  7. hibernate_validator_03

    约束继承 如果要验证的对象继承于某个父类或者实现了某个接口,那么定义在父类或者接口中的约束会在验证这个对象的时候被自动加载,如同这些约束定义在这个对象所在的类中一样. 让我们来看看下面的示例: pac ...

  8. 修路方案(nyoj)

    算法:次小生成树 描述 南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路. 现在已经知道哪些城市之间可以修路,如果修路,花费是多少. 现在 ...

  9. 【USACO 3.1.6】邮票

    [描述] 已知一个N枚邮票的面值集合(如,{1分,3分})和一个上限K ——表示信封上能够贴K张邮票.计算从1到M的最大连续可贴出的邮资. 例如,假设有1分和3分的邮票:你最多可以贴5张邮票.很容易贴 ...

  10. MYSQL主从不同步延迟原理

    1. MySQL数据库主从同步延迟原理.   要说延时原理,得从mysql的数据库主从复制原理说起,mysql的主从复制都是单线程的操作,   主库对所有DDL和DML产生binlog,binlog是 ...