1、变量

我们可能产生这样一个疑问:编程语言中的变量到底是什么意思呢?

事实上,当我们定义了一个变量a时,就是在存储器中指定了一组存储单元,并将这组存储单元命名为a。变量a的值实际上描述的是这组存储单元中存放的具体信息。

例如,在JS中

var a;
a=10;

第一个语句在存储器中指定了一组存储单元,并命名为a;

第二个语句在这组存储单元中存储了数字10。

变量a的值为10实际上是说存储单元组a存储的信息是10。

假使我们再次对a进行复制操作:

a="hello";

这样a的值变成字符串”hello"。这很容易理解,我们将存储单元组a中存储的信息改为字符串”hello",显然原先的数字10将被覆盖。

2、指针

假使我们在另一个变量b中存储变量a在存储器的地址,会发生什么?

我们很容易想到,直接访问b变量,得到的并不是变量a的值,而是变量a在存储器中的地址,变量b便被称为指针。

这样一个问题产生了:如何通过变量b访问到变量a的值呢?

在C语言中,常用的是用*,比如:

int c=10,b;
int *p;/*p是指向int类型的指针*/
p=&c;/* &c获取变量c的地址,然后赋值给变量p,这样p存储的是变量c的地址,即p是指向c的指针*/
b=*p;/* *p访问p指向的对象,然后将值赋值给b*/

在JS中,并没有指针这种变量类型,但指针的应用却无处不在。比如:

var o1={b:1};
var o2={b:1};
o1===o2;//false
o1==o2;//false

这里o1和o2都是相同的对象,为什么不相等呢?这就需要深入理解JavaScript中的引用类型和指针。

首先,我们需要明白:

给o1和o2赋值,并不是o1地址中存储对象{b:1},o2地址中也存储对象{b:1}。

其次,我们要明白实际发生的操作:

var o1={b:1}实现了在堆内存中创建了一个对象{b:1},o1则存储了该对象在堆内存中的地址,即o1是一个指针,指向{b:1};

同理,var o2={b:1}也在堆内存中创建了一个对象{b:1},o2存储了该对象在堆内存中的地址,即o2也是一个指针,指向{b:1};

并且,由于两个相同的对象{b:1}是先后创建,在堆内存中也不是存储在相同的地址。

然后,我们还需要知道:

在JavaScript中,引用类型(对象、数组、正则、Date、函数)的比较,实际上是比较指针是否指向存储器中的同一段地址,只有指向同样的地址才能相等。

显然,o1这个指针指向堆内存中创建的第一个对象{b:1};

o2指针则指向堆内存中创建的第二个对象{b:1};

但两个对象相对独立,并不是同一个对象,故o1和o2并没有指向同样的堆内存地址,故而并不相等。

我们再看常见的应用:

var o={a:1};
o.__proto__===Object.prototype;//true

对象o的构造函数是Object,Object有一个prototype属性,并且prototype是一个指针,他指向存储器中的一个对象,此对象将会被由构造函数创建的对象实例所共享。

作为Object的实例,o也有一个指针__proto__,它也指向Object的prototype属性指向的对象。

这里的全等返回true,则清楚地表明了两者指向同样的堆内存地址,即指向的是同一个对象。

我们如果想主动让两个引用类型指向同样的对象,如何操作呢?

var obj1={b:1};
var obj2=obj1;
obj1===obj2;//true
obj1==obj2;//true

可以看到,对于引用类型,直接使用’='赋值实际上就是使两者指向同一个对象。

故而,我们猜测,如果通过obj1修改了对象的值,obj2再次访问时将看到修改后的对象:

obj1.name='ls';
obj1;//{b: 1, name: "ls"}
obj2;//{b: 1, name: "ls"}

的确如此。作为对比:

o1.name='ls';
o1;//{b: 1, name: "ls"}
o2;//{b: 1}

那么,对于基本类型呢?

var s1=1;
var s2=2;
s1===s2;//true

在JS中,对于基本类型,只需其值相等,则两个变量就相等。

3、引用

首先,我们要深入理解引用类型的值。

前面我们看到,obj1和obj2指向堆内存中存储的同一个对象。当我们访问obj1和obj2时,都会返回同一个对象。可以说:obj1的值和obj2的值相同。

对于o1和o2,他们指向堆内存中不同地址的两个{b:1}对象,o1和o2拥有不同的值。

因此,对于引用类型,我们所说的值,指的是保存在内存中的对象。如果是同一对象,则值相同,不同对象则值不同。

在JS中,传递参数都是按值传递的。比如:

var a1=1,b1=2;
function add(a,b){
a++;
b--;
return a+b;
};
add(a1,b1);//3
a1;//1
b1;//2

这里,函数add中的形参a、b分别得到变量a1、b1的值的拷贝,这便是按值传递。

在add函数执行环境中对a、b操作不会影响到全局变量a1、b1。

再看引用类型:

 function setName(obj){
obj.name="Nicholas";
obj=new Object();
obj.name="Greg";
}
var person=new Object();
setName(person);
alert(person.name);//"Nicholas"

执行setName(person)时,person指向的内存中的地址便被传入obj,使得obj也指向同样的内存地址,即同一个对象。这里的按值传递,传递的是内存地址。

如果通过obj修改该对象,外部访问person便也能体现出来。

我们可能有一个疑问,既然是指向同一个对象,为什么不是按引用传递呢?

首先,我们看到函数内部对obj重新进行了赋值,使得obj指向新创建的对象。如果是按引用传递,那么外部person便也会指向新创建的对象。实际上,person还是指向原先的对象。

对于引用类型的按值传递,其实可以更加通俗地理解:

1、实参将指向的内存地址传递给形参 ,按值传递的值指的是内存地址;

2、形参修改了它和实参共同指向的对象后,外部的实参会反映出来;

3、但形参始终无法修改实参指向的内存地址,即如果将形参指向新的对象,实参并不会指向新的对象。

基于以上3点,我们就不难理解上面代码运行的结果了。

谈谈JavaScript中的变量、指针和引用的更多相关文章

  1. Javascript 判断 iframe 中的变量是否为对象

    Javascript 判断 iframe 中的变量是否为对象 前言 公司之前的项目中,为了实现模块化,在 web 后端使用了 iframe 来组织框架和页面.由于当时没有很好地规划,iframe 子页 ...

  2. 谈谈java中静态变量与静态方法在有继承关系的两个类中调用

    谈谈java中静态变量与静态方法在有继承关系的两个类中调用 学习的中如果遇到不明白或者不清楚的的时候,就是自己做些测试,自己去试试,这次我就做一个关于静态变量和静态方法在有继承关系的两个类中的问题测试 ...

  3. 谈谈java中成员变量与成员方法继承的问题

    谈谈java中成员变量与成员方法继承的问题 关于成员变量和成员方法的的继承问题,我也可以做一个小测试,来看看结果. 首先我们先创建一个父类:

  4. <javaScript>谈谈JavaScript中的变量、指针和引用

    1.变量我们可能产生这样一个疑问:编程语言中的变量到底是什么意思呢?事实上,当我们定义了一个变量a时,就是在存储器中指定了一组存储单元,并将这组存储单元命名为a.变量a的值实际上描述的是这组存储单元中 ...

  5. <JavaScript>谈谈javascript语法里一些难点问题(一)

    1)    引子 前不久我建立的技术群里一位MM问了一个这样的问题,她贴出的代码如下所示: var a = 1; function hehe() { window.alert(a); var a = ...

  6. PHP中静态变量和函数引用返回

    这两天看看PHP写的框架CI,源代码中写了很多静态变量和函数引用. 官方文档地址:http://php.net/manual/zh/language.references.return.php 简单写 ...

  7. javascript 及 vue 中的变量前面的美元符号 $ 是什么意思

    $ 您会注意到,我们将库代理为以美元符号“$”为前缀的属性名. 你可能还看过其他的属性和方法,例如,$refs, $on, $mount等等也都是以”$”开头. 虽然属性名上添加前缀不是必须的,但是这 ...

  8. 关于javascript在作用域中的变量定义你所不知道的一些东西

    //先看一段代码 var a = 100; function test(){ alert(a); var a = 200; } test(); /* 结果:undifined 原因:js引擎在执行sc ...

  9. mybatis中的变量#与$

    ibatis中使用select top #num# * from tableName出现错误.由于初次用ibatis还不知道在它里边拼写SQL语句的一些规则,导致一些自认为很平常的SQL语句,在它这里 ...

随机推荐

  1. http之抽丝剥茧,深度剖析http的那些事儿

    最近,小编一心扎跟学技术,毫不顾及头发的掉落速度,都快成地中海了,不过也无大碍,谁让咱是一个爱钻技术的男人呢.最近两周老是看到http,那么这个http,有哪些猫腻呢,很多同学都有这种理解,就是对于h ...

  2. 家庭记账本app进度之下拉框和数字转轮的相关应用

    这次主要是悬系的下拉框Spinner和数字转轮NumberPicker的使用.先分析相关的用到的知识点. 在Android中,用string-array是一种简单的提取XML资源文件数据的方法. 例子 ...

  3. html的嵌套规则

    html元素分为块状元素和内联元素,块状元素作为其他元素的容器. 块状元素可以嵌套其他块状元素 块状元素可以嵌套内联元素 内联元素不能嵌套块状元素 p内不能嵌套块状元素 有几个特殊块状元素只能包含内联 ...

  4. Python之 module安装

    如出现这种错误 ModuleNotFoundError: No module named 'numpy' 这种错误通常不会出现,因为Python的模块,通常在你安装Python shell的时候,就已 ...

  5. Array(数组)对象-->reverse() 方法

    1.定义和用法 reverse() 方法用于颠倒数组中元素的顺序:倒序. 语法: array.reverse() 举例: var arr = [1,2,3,4,5]; console.log(arr. ...

  6. Python Requests-学习笔记(11)-请求与响应对象

    任何时候调用requests.*()你都在做两件主要的事情.其一,你在构建一个 Request 对象, 该对象将被发送到某个服务器请求或查询一些资源.其二,一旦 requests 得到一个从 服务器返 ...

  7. spark rdd元素println

    1.spark api主要分两种:转换操作和行动操作.如果在转化操作中println spark打印了 我也看不到. val result = sqlContext.sql(sql) val resu ...

  8. hadoop(十)hdfs上传删除文件(完全分布式七)|12

    集群测试 上传小文件到集群,随便选择一个小文件上传到hdfs的根目录 [shaozhiqi@hadoop102 hadoop-3.1.2]$ bin/hdfs dfs -put wcinput/wc. ...

  9. AJ学IOS 之微博项目实战(13)发送微博调用相机里面的图片以及调用相机

    AJ分享,必须精品 一:效果 二:代码 相机部分就简单多了,几行代码调用而已,但是如果你要是想实现更多丰富的功能,需要自己写.利用AssetsLibrary.framework,利用这个框架可以获得手 ...

  10. Supermarket POJ - 1456(贪心)

    题目大意:n个物品,每个物品有一定的保质期d和一定的利润p,一天只能出售一个物品,问最大利润是多少? 题解:这是一个贪心的题目,有两种做法. 1 首先排序,从大到小排,然后每个物品,按保质期从后往前找 ...