引用传递与值传递

Posted 古兰精

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了引用传递与值传递相关的知识,希望对你有一定的参考价值。

一、ECMAScript中的数据类型

1、基本数据类型:null、undefined、number、boolean、string

2、引用数据类型:object(obj、[]、{}、function、RegExp等),是由一组无序的名值对组成的

3、typeof与instanceof作用:

  typeof是用来检测这些基本数据类型的:

返回“underfined”,表示这个值只是被声明了,却没有给其定义,也可以理解为没有赋值

返回“boolean”表示这个值是布尔值,布尔值的运用大多时候是结合表达式的

返回”string“表示这个值是字符串

返回”number“表示这个值是数值

返回”object“表示这个值是对象或者null(此处也体现出js的松散性,似乎显得不够严谨,但正是这个特性使得js更为灵活了,此处null被认为是一个空的对象引用也就是空的对象指针,所以返回object)

返回”function“ 表示这个值是函数,其实函数也是对象,js是面向对象的,所以有种说法,js中一切皆对象,只是这里调用typeof返回了function,这也说明了function是对象里的一个特例,有其不同之处。

  instanceof,主要是用以检测引用类型的值,可以检测到具体的引用类型的实例,返回结果true或者false;比如:

alert(person instanceof Object);// 变量person是对象吗?

alert(colors instanceof Array);//变量colors是数组吗?

alert(pattern instanceof RegExp);//变量pattern是RegExp吗?

二、2种数据类型的区别

1、存储方式不同:简单数据类型存储在栈内存中,引用数据类型存储在堆内存

2、访问方式不同:简单数据类型直接访问其值,操作时也是直接对其值进行操作;引用数据类型是按引用进行访问,要访问的值得根据其引用路径一直找到那个最终的值

3、值传递方式不同:简单数据类型复制的时候,新出现的变量会重新产生一个栈内存地址,来保存新值,与原变量没有关系复杂数据类型值的传递是按引用进行的,来个不是很恰当的比喻,引用传递有点像身份证复印件,可以有很多份复印件但都是来源于身份证,其实引用值传递复制的是存储在栈中的指针,这个复制而来的指针和之前的指针指向的是存储在堆中的同一个对象。

三、栈内存和堆内存:

  Java把内存分成两种,一种叫做栈内存,一种叫做堆内存。

  在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。

  堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址(与C语言一样),在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名,或者代号

  引用变量是普通变量,定义时在栈中分配内存,引用变量在程序运行到作用域外释放。而数组&对象本身在堆中分配,即使程序运行到使用new产生数组和对象的语句所在地代码块之外,数组和对象本身占用的堆内存也不会被释放,数组和对象在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。

  这个也是java比较占内存的主要原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!

  理解:引用变量实际上就是指向堆内存里内容的指针。

四、引用传递和值传递

实例:

function createObject(name,qq){
    this.name = name;
    this.qq = qq;
}
createObject.prototype.show = function(){
    alert(this.qq);
}
//继承
function B(){
    createObject.call(this);
}
B.prototype = createObject.prototype;//此种写法是错误的哈,会改变createObject.prototype的内容
B.prototype.fn = function(){
    alert("B");
}
var objB = new B();
var objA = new createObject("tom","814991269");
objA.fn();

发现 objA 可以访问到 fn 函数,打印 createObject.prototype 发现和 B.prototype 一样,这就是因为引用传递的问题:互相影响。实际上 B.prototype 是指向 createObject.prototype 的地址的,B.prototype 变化,即 createObject.prototype 变化。

var a = [1,2,3];
var b = a;
b.push(4);
console.log(a);//[1,2,3,4]
a.push(5);
console.log(b);//[1,2,3,4,5]
console.log(a === b);//true

正确的写法是:

function createObject(name,qq){
    this.name = name;
    this.qq = qq;
}
createObject.prototype.show = function(){
    alert(this.qq);
}
//继承
function B(){
    createObject.call(this);
}
for(var i in createObject.prototype){
    B.prototype[i] = createObject.prototype[i];
}//这样写B.prototype就是开辟了新的内存空间,而不是指向createObject.prototype,就不会影响到createObject.prototype
B.prototype.fn = function(){
    alert("B");
}
var objB = new B();
var objA = new createObject("tom","814991269");
objA.fn();//fn is not a function 错误

 

以上是关于引用传递与值传递的主要内容,如果未能解决你的问题,请参考以下文章

Java 参数传递与值传递

区别PHP引用传递与值传递的小例子

C/C++ 引用与值传递的问题?

python numpy 和内存效率(通过引用与值传递)

引用传递与值传递______深拷贝与浅拷贝______构造函数与析构函数

通过引用而不是按值传递 OpenCV C++