JavaScript的值传递和引用传递

本文和大家分享的主要是javascript中值传递和引用传递相关内容,一起来看看吧,希望对大家学习javascript有所帮助。

JavaScript有5种基本的数据类型,分别是:布尔、null、undefined、String和Number。这些基本类型在赋值的时候是通过值传递的方式。值得注意的是还有另外三种类型: Array、Function和Object,它们通过引用来传递。从底层技术上看,它们三都是对象。

基本数据类型

如果一个基本的数据类型绑定到某个变量,我们可以认为该变量包含这个基本数据类型的值。

var x = 10;var y = ’abc’;var z = null;

当我们使用 = 将这些变量赋值到另外的变量,实际上是将对应的值拷贝了一份,然后赋值给新的变量。我们把它称作 值传递 。

var x = 10;var y = ’abc’;

var a = x;var b = y;

console.log(x, y, a, b) // 10, ’abc’, 10, ’abc’

a 和 x 都包含10, b 和 y 都包含 ’abc’ ,并且它们是完全独立的拷贝,互不干涉。如果我们将 a 的值改变, x 不会受到影响。

var x = 10;var y = ’abc’;var a = x;var b = y;

a = 5;

b = ’def’;console.log(x, y, a, b); // 10, ’abc’, 5, ’def’

对象

如果一个变量绑定到一个非基本数据类型(Array, Function, Object),那么它只记录了一个内存地址,该地址存放了具体的数据。注意之前提到指向基本数据类型的变量相当于包含了数据,而现在指向非基本数据类型的变量本身是不包含数据的。

对象在内存中被创建,当我们声明 arr = [] ,我们在内存中创建了一个数组。 arr 记录的是该内存的地址。

var arr = []; // (a)

arr.push(1); // (b)

当执行完(a)之后,内存中创建了一个空的数组对象,其内存地址为 #001 , arr 指向该地址。

变量地址对象

arr#001[]

当执行完(b)之后,数组对象中多了一个元素,但是数组的地址依然没有变, arr 也没有变。

变量地址对象

arr#001[1]

引用传递

对象是通过引用传递,而不是值传递。也就是说,变量赋值只会将地址传递过去。

var reference = [1];var refCopy = reference;

变量地址对象

reference#001[1]

refCopy#001

reference 和 refCopy 指向同一个数组。 如果我们更新 reference , refCopy 也会受到影响。

reference.push(2);console.log(reference, refCopy); // [1, 2], [1, 2]

变量地址对象

reference#001[1, 2]

refCopy#001

引用重新赋值

如果我们将一个已经赋值的变量重新赋值,那么它将包含新的数据或则引用地址。

var obj = { first: ’fundebug.com’};

obj = { second: ’fundebug.cn’};

obj 从指向第一个对象变为指向第二个对象。

变量地址对象

obj#001{first: ‘fundebug.com’}

#002{second: ‘fundebug.cn’}

如果一个对象没有被任何变量指向,就如第一个对象(地址为 #001 ),JavaScript引擎的垃圾回收机制会将该对象销毁并释放内存。

== 和 ===

对于引用类型的变量, == 和 === 只会判断引用的地址是否相同,而不会判断对象具体里属性以及值是否相同。因此,如果两个变量指向相同的对象,则返回 true 。

var arrRef = [’Hi!’];var arrRef2 = arrRef;

console.log(arrRef === arrRef2); // true

如果是不同的对象,及时包含相同的属性和值,也会返回 false 。

var arr1 = ["Hi!"];var arr2 = ["Hi!"];

console.log(arr1 === arr2); // false

如果想判断两个不同的对象是否真的相同,一个简单的方法就是将它们转换为字符串然后判断。

var arr1str = JSON.stringify(arr1);var arr2str = JSON.stringify(arr2);

console.log(arr1str === arr2str); // true

另一个方法就是递归地判断每一个属性的值,直到基本类型位置,然后判断是否相同。

函数参数

当我们将基本类型数据传入函数,函数会将这些数据拷贝赋值给函数的参数变量。

var hundred = 100;var two = 2;function multiply(x, y){

return x * y;

}var twoHundred = multiply(hundred, two);

hundred 的值拷贝给变量 x , two 的值拷贝给变量 y 。

纯函数

对于一个函数,给定一个输入,返回一个唯一的输出。除此之外,不会对外部环境产生任何附带影响。我们机会称该函数为纯函数。所有函数内部定义的变量在函数返回之后都被垃圾回收掉。

但是,如果函数的输入是对象(Array, Function, Object),那么传入的是一个引用。对该变量的操作将会影响到原本的对象。这样的编程手法将产生附带影响,是的代码的逻辑复杂和可读性变低。

因此,很多数组函数,比如 Array.map 和 Array.filter 是以纯函数的形式实现。虽然它们的参数是一个数组变量,但是通过深度拷贝并赋值给一个新的变量,然后在新的数组上操作,来防止原始数组被更改。

我们来看一个例子:

function changeAgeImpure(person){

person.age = 25;

return person;

}var alex = {

name: ’Alex’,

age: 30

};

var changedAlex = changeAgeImpure(alex);

console.log(alex); // { name: ’Alex’, age: 25 }

console.log(changedAlex); // { name: ’Alex’, age: 25 }

在非纯函数 changeAgeImpure 中,将对象 person 的 age 更新并返回。原始的 alex 对象也被影响, age 更新为25。

让我们来看如何实现一个纯函数:

function changeAgePure(person){

var newPersonObj = JSON.parse(JSON.stringify(person));

newPersonObj.age = 25;

return newPersonObj;

}var alex = {

name: ’Alex’,

age: 30

};

var alexChanged = changeAgePure(alex);

console.log(alex); // { name: ’Alex’, age: 30 }

console.log(alexChanged); // { name: ’Alex’, age: 25 }

我们通过 JSON.sringify 将对象变为一个字符串,然后再通过 JSON.parse 将字符串变回对象。通过该操作会生成一个新的对象。

一道简单的面试题

值传递和引用传递经常在面试中被问到,来尝试回答一下如下代码如何输出:

function changeAgeAndReference(person){

person.age = 25;

person = {

name: ’John’,

age: 50

};

return person;

}var personObj1 = {

name: ’Alex’,

age: 30

};

var personObj2 = changeAgeAndReference(personObj1);

console.log(personObj1); // -> ?

console.log(personObj2); // -> ?

来源:Fundebug博客

时间: 2024-07-29 13:53:09

JavaScript的值传递和引用传递的相关文章

JavaScript强化教程——对象的值传递和引用传递

本文为 H5EDU 机构官方 HTML5培训 教程,主要介绍:JavaScript强化教程--对象的值传递和引用传递 function SetName(obj){  obj.name="Tom";//执行之前,此时的obj和Person的name属性均为undefined  obj1=new Object();  obj1=obj;//声明一个全局对象,那么obj.obj1和Person此时应该是同一个对象  }//SetName函数执行完之后,obj对象销毁,其余对象仍然存在  Pe

Javascript 之《函数传参到底是值传递还是引用传递》

前言 这个问题其实困惑了我好久,但是在实际使用中总是得过且过,不想去深究.由于这种态度,在学习 Javascript 过程中,水平一直都是出于半桶水状态,很多概念和原理似懂非懂,模糊不清. 所以,写了一系列的<Javascript 之 ...>就是为了端正态度,认真地研究一下 Javascript 的特性和原理,夯实基础. 今天,这一篇探究的是函数传参的问题:函数传参到底是传值还是传的引用? 1.如果是引用传递 var name = 'JS'; function changeName(name

JavaScript 函数参数传递到底是值传递还是引用传递

tips:这篇文章是听了四脚猫的js课程后查的,深入的理解可以参看两篇博客: JavaScript数据类型--值类型和引用类型 JavaScript数据操作--原始值和引用值的操作本质 在传统的观念里,都认为JavaScript函数传递的是引用传递(也称之为指针传递),也有人认为是值传递和引用传递都具备.那么JS的参数传递到底是怎么回事呢?事实上以下的演示也完全可以用于Java 首先来一个比较简单的,基本类型的传递: function add(num){ num+=10; return num;

254 在js调用函数时,传递变量参数时, 是值传递还是引用传递

问题: 在js调用函数时,传递变量参数时, 是值传递还是引用传递 理解1: 都是值(基本/地址值)传递 理解2: 可能是值传递, 也可能是引用传递(地址值) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>02_关于数据传递问题</title> </head> <body> <

值传递,指针传递;引用传递(c++独有)本质

要理解值传递.指针传递和引用传递的区别,主要要理解函数的实参和形参,函数的作用域(自动变量.栈),内存的布局以及指针和引用的特点.这里主要总结三种参数传递方式使用的主要场合. 值传递:只给函数提供输入值,需要复制开销,大对象很少使用值传递. 指针传递:可以改变指针指向内容的值,但是不能改变指针本身,无需复制开销.如果需要改变指针本身,可以使用二重指针或者指针引用. 引用传递:除了提供输入值外,还返回操作结果,无需复制开销. #include<stdlib.h> //值传递,函数体内变量n是参数

Java中的值传递和引用传递

解释 1.Java中有没有引用传递? 答:Java中只有按值传递,没有按引用传递! 2.当一个对象被当作参数传递到一个方法中后,在此方法中可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 答:是值传递. Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言).如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,这个跟之前所谈的传值是一样的,如果在函数中改变了副本

c# 值类型与引用类型 值传递与引用传递

值类型与引用类型: 值类型 :1.值类型大小固定.存储在栈上.  2.不能继承,只能实现接口 3.派生自valuetype int double char float byte bool enum struct decimal 引用类型:1.在栈上存储了一个地址实际存储在堆中,大小不固定. 2.数组.类.接口.委托 string 数组 类 接口 委托 值传递与引用传递: 值类型按值传递.值类型按引用传递.引用类型按值传递.引用类型按引用传递. 值传递:默认传递都是值传递 ,把栈中内容拷贝一份引用

java中参数传递--值传递,引用传递

java中的参数传递--值传递.引用传递 参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递. 在 Java 应用程序中永远不会传递对象,而只传递对象引用.因此是按引用传递对象.Java 应用程序按引用传递对象这一事实并不意味着 Java 应用程序按引用传递参数.参数可以是对象引用,而 Java 应用程序是按值传递对象引用的. Java 应用程序中的变量可以为以下两种类型之一:引用类型或基本类型.当作为参数传递给一个方法时,处理这两种类型的方式是相同的.两

java中值传递和引用传递

本来今天刚学习的内容,然后去其他博客看了下,发现都吵起来了,就是名字原因,有的说java有值传递和引用传递,有的说引用传递本质就是值传递,我管你杂说的,只要自己理解好,代码知道运行结果就好了. 我用自己的话,自己的理解来解释下,反正都是自己写着玩,自己看的 值传递:传递的值,这个值以后怎么改变,源值不会发生改变的. 引用传递:将对象的引用地址传递过去,如果值发生改变,那么源值也发生改变. 代码如下: 值传递: public class Test1 { public static void mai