引言

JavaScript的变量本质是松散类型的,也就是说其变量就是用于保存特定值的一个名字,变量的值和数据类型可以在脚本执行的生命周期中发生变化。这是一个很有趣很强大的特性,但是也是一个极容易出错误的地方。

两大类型

基本类型:指的是简单的数据段,有五种基本类型:Undefined,Null,Boolean,Number,String。这几种基本类型是按值访问的,操作变量时操作的是保存在变量中实际的值。

引用类型:指哪些可能由多个值构成的对象(Object)。引用类型的值是保存在内存中的对象。需要注意的是,JavaScript不允许直接访问内存中的位置,所以操作对象时,实际是操作对象的引用(这种说法是不严谨的,因为当复制保存对象的变量时,操作的是对象的引用;但是在为对象添加属性时,操作的是对象实际本身)。

变量的复制

基本类型变量的复制

当复制基本类型的变量时,实际是在变量对象上创建一个新值,然后把这个创建的新值分配给为新变量复制的位置上。所以原始变量和被赋值的变量在内存中是独立的,这两个变量可以参与任意操作而不会相互影响

var a = 'test';
var b = a;
a = 'change';
console.log(b);
//输出:test

 

引用类型变量的复制

当复制引用变量的值时,也是讲存储在变量对象中的值复制一份放在新变分配的空间中。但是这里需要理解的是,这个值的副本实际是一个指针,而这个指针指向存储在堆内存中的一个对象。上面已经说过了:对于引用类型的变量,JavaScript不允许直接操作对象,而是操作对象的引用,所以在引用变量中存储的是一个指向实际存储空间的指针。复制结束后两个变量实际引用的一个对象,所以改变其中一个变量,另一个将会受到影响。

var a = new Object();
var b = a;
a.title = 'test';
console.log(b.title);
//输出:test

保存在变量对象中的变量和保存在堆中的对象之间的关系(不要在意图片丑~)

参数传递

在ECMAScript中所有函数的参数都是按值传递的。什么意思呢?就是把函数体外面的值复制给函数内部的参数(如同把值从一个变量复制到另一个变量一样)。这样子就很好理解了。和理解了上面变量的复制,也就很好理解js中参数的传递特性了。

在向参数传递基本类型值时,被传递的值会被赋值给一个局部变量,即函数体的命名参数(在ECMAScript中就是arguments对象中的一个元素)。在向参数传递引用类型的值时,会把这个值在内存中的地址赋值给参数。

function setName(n) {
n = 'test';
return n;
}
var a = 'haha';
var b = setName(a);
console.log(a);
console.log(b);
//输出:
//haha
//test

如果使用引用类型作为参数:

function setName(obj) {
obj.name = 'shanlei';
}
var a = new Object();
setName(a);
console.log(a.name);
//输出:shanlei

在这个函数中obj和a引用的是同一个对象,挡在setName中添加name属性后,函数外部也会有所反应。在这里有人可能会错误的认为在局部作用域中修改的对象会在全局作用域中反映出来,就是说明这个参数是按引用传递的。这个思想是错误的。可以看下面这个例子:

function setName(obj) {
obj.name = 'shanlei';
obj = new Object();
obj.name = 'Grep';
}
var a = new Object();
setName(a);
console.log(a.name);
//输出:shanlei

在这段中,我们将obj重新定义了一个对象,并且给这个新对象定义一个不同值的name属性。如果参数是按引用传递的,那么a应该会自动被修改为指向其name属性设置为'Grep'的新对象。因为如果参数是以引用传递的,那么obj和a应该是统一引用,这个引用指向堆中实际存储对象的空间。当生成一个新的对象设置新的name属性并将这个新对象给obj时,实际上就是改变了这个引用在堆中的指向,所以外部的a也就会自动改变。而输出的依旧是'shanlei',这说明在函数内部修改了参数的值,但原始的引用依旧没有改变。因为obj和a在内存中是两个独立的变量对象,这两个变量对象指向堆中同一空间,当生成新对象并传递给obj时,obj的指向发生改变,但是a的指向依旧是堆中原始的空间,所以输出的依旧是‘shanlei’。当在函数内部重写obj时,这个变量引用就是一个局部对象,且这个局部对象在函数执行完毕以后会立即销毁。

以上~~

JavaScript变量那些事的更多相关文章

  1. javascript变量的作用域

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

  2. JavaScript 变量声明提前

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

  3. JavaScript 变量

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

  4. javascript变量声明 及作用域

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

  5. JavaScript 变量作用域

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

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

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

  7. JavaScript变量和数据类型

    变量 变量就是一个元素,类似于数学中的概念,用来指定表示一个对象.在JavaScript中,用来指定变量的关键字为var.当声明新变量时,可以使用关键词 "new" 来声明其类型 ...

  8. 回归基础: JavaScript 变量提升

    from me: javascript的变量声明具有hoisting机制,它是JavaScript一个基础的知识点,也是一个比较容易犯错的点,平时在开发中,大大小小的项目都会遇到. 它是JavaScr ...

  9. JavaScript - 变量,作用域,内存

    JavaScript 变量可以用来保存两种类型的值:基本类型值和应用类型值.基本类型的值源自以下5种基本数据类型:Undefined.Null.Bollean.Number和String. 所有变量都 ...

随机推荐

  1. Associate File Type with Qt In Mac Os and Win

    Win Registry Question One day, my boss want me to finish one function which let the users can double ...

  2. oracle删除表空间下所有的表

    SELECT 'DROP TABLE ' || TABLE_NAME || ' CASCADE CONSTRAINTS' V_NAME FROM DBA_TABLES WHERE TABLESPACE ...

  3. JavaScript RegExp.test() 方法

    定义和用法: test() 方法用于检测一个字符串是否匹配某个模式. 语法: RegExpObject.test(string); RegExpObject:正则表达式; string:必须参数,要检 ...

  4. [Selenium] 怎样判断是否适合自动化测试

    实施自动化测试前需要对软件开发过程进行分析,以观察其是否适合使用自动化测试.通常需要满足以下条件: 1)需求变动不频繁 2)项目周期足够长 3)自动化测试脚本可重复使用 4)手工测试无法完成或者需要大 ...

  5. [SoapUI]怎样获取上一个Test Step的名字

    def currentStepInd = context.currentStepIndex def previousStep = testRunner.testCase.getTestStepAt(c ...

  6. Java开发环境之------MyEclipse快捷键和排除错误第一选择ctrl+1(***重点***:ctrl+1,快速修复---有点像vs中的快速using

    using Java开发环境之------MyEclipse快捷键和排除错误第一选择ctrl+1(***重点***:ctrl+1,快速修复---有点像vs中的快速using 2015-06-29 浏览 ...

  7. Maven项目下java.lang.ClassNotFoundException常规解决办法

    网上很多要修改.class .project的比较麻烦有时候还不一定管用.下面的方法适合于项目用已经引用了jar,但是运行时却ClassNotFound,请用如下方法试试: 严重: Error con ...

  8. mongo学习- 副本集配置(事故自动转移)

    一.安装mongodb 二.复制2份 三.启动 (1)mongod --config C:\mongofuben\zhu\conf\mongodb.config --replSet haibin/12 ...

  9. 在Linux下使用logrotate管理日志(转)

    原文地址:http://www.tuicool.com/articles/ieAnMjN logrotate是日志循环管理工具,可以分割日志文件,删除旧的日志文件,创建新的日志文件,循环管理日志从而节 ...

  10. http://www.rabbitmq.com/

    什么是RabbitMQ 官网http://www.rabbitmq.com/ 1.应用程序间健壮的消息发送 2.简单易用 3.可在所有主流操作系统运行 4.支持巨量的开发者平台 5.开源和商用双重支持 ...