资讯专栏INFORMATION COLUMN

深入理解javascript按值传递与按引用传递

陈江龙 / 2161人阅读

摘要:引用类型参数的传递与引用类型的复制一样,传递的是内存地址。指向一个新的地址,与不再指向同一个地址官方解释来一发中所有函数的参数都是按值传递的。总结很简单,函数参数都是按值传递都是栈内数据的拷贝。

基本类型与引用类型

值类型(基本类型):String,Number,Boolean,Null,Undefined。
引用类型:Array、Object、Function、Date等有多个值构成的可变长度的复杂类型。

基本类型与引用类型有什么区别?

(1)基本类型的变量保存的是变量值,引用类型的变量保存的是内存地址;
(2)基本类型长度固定,在内存中占据固定大小的空间,数据存放在栈内存中;引用类型可以给对象添加属性和方法,长度不固定,数据存放在堆内存中。引用类型的存储需要栈区和堆区(堆区是指内存里的堆内存)共同完成,栈区内存保存变量标识符和指向堆内存中该对象的指针,也可以说是该对象在堆内存的地址;
(3)基本类型在赋值的时候拷贝值,引用类型在赋值的时候只拷贝地址,不拷贝值。

基本类型与引用类型的复制
const num1 = 5;
const num2 = num1;

const obj1 = {};
const obj2 = obj1;

基本类型复制与引用类型复制,看不懂直接上代码!!
// 测试引用类型传值和数组类型传值
const obj = {
  success: false,
  result: {
    name: "222"
  }
};
let name = obj && obj.result && obj.result.name; // name为一个str,具体的值为基础类型,name这里保存的是变量值,而不是引用地址
console.log(name); // 222
name = "333";
console.log(obj.result.name); // 222, name为变量值,name的改变并不会影响到obj.result.name
obj.result.name = "44444";
console.log(obj.result.name); // 44444
console.log(name); // 333,name为变量值,而非引用地址,与obj.result.name相互不影响,因此obj.result.name的改变也不会引起name的变化
const obj = {
  success: false,
  result: {
    name: "222"
  }
};
let result = obj && obj.result;
console.log(result);  // { name: "222" },obj.result是一个Object类型,这里result存的是obj.result的引用地址,result和obj.result指向堆中的同一个地址,相互影响
obj.result.name = "44444";
console.log(obj.result.name); // "44444"
console.log(result); // { name: "44444" }
result.name = "xxxxx"; // 属性修改,相互影响
console.log(obj.result); // { name: "xxxxx" }
// result重新赋值,指向一个新的引用地址,此时result与obj.result指向不同地址,不再相互影响
result = {
  name: "ooooo"
};
console.log(result); // { name: "ooooo" }
console.log(obj.result); // { name: "xxxxx" }
const obj = {
  success: false,
  result: [0, 1]
};
let result = obj && obj.result;
console.log(result); //[0, 1],obj.result为Array类型,result和obj.result指向堆中的同一个地址,相互影响
console.log(obj.result); // [0, 1]
result.push("aa"); // 数组的push操作是在原数组基础上操作,并不生成一个新的数组,result和obj.result依然指向同一个地址,相互影响
console.log(result); // [0, 1, "aa"]
console.log(obj.result); // [0, 1, "aa"]
result = [0, 1, 2]; // result重新赋值,此时result指向堆中一个新的地址,result与obj.result指向不同地址,不再相互影响
console.log(obj.result); // [0, 1, "aa"]
console.log(result); // [0, 1, 2]
函数参数传递按值类型还是引用类型?

基本类型参数的传递与基本类型的复制一样,传递的是变量值。

function addTen(num) {
   num = num + 10;
   return num;
}
var count = 20;
var result = addTen(count);
console.log(count); // 20
console.log(result); // 30

引用类型参数的传递与引用类型的复制一样,传递的是内存地址。

function setName(obj){
   obj.name = "xxx";
   obj = {name: "ppp"}; // obj指向一个新的地址,与person不再指向同一个地址
   console.log(obj.name); // "ppp"
}
const person = {name : "oo"};
setName(person);
console.log(person.name); // ‘xxx’
官方解释来一发:

ECMAScript中所有函数的参数都是按值传递的。

也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型的传递如同基本类型的复制一样,而引用类型值的传递,如同引用类型变量的复制一样。

总结

很简单,javascript函数参数都是按值传递(都是栈内数据的拷贝)。 
基本类型传的是值本身(因为直接把值存在栈内),引用类型传的是对象在内存里面的地址 (因为复杂对象存在堆内,所以在栈里存对象所在的堆地址)。
基本类型与引用类型的检测

typeof是检测基本数据类型的最佳工具,但是对检测引用类型,返回的都是object,并不能确定是哪种类型的对象,没有意义。

基本类型:基本类型中的null,返回为object,其他的都能正常检测出准确的类型。
typeof("aa"); // "string"
typeof(123); // "number"
typeof(NaN); // "number"
typeof(cc); // "undefined" 未定义变量undefined
typeof(undefined); // "undefined"
typeof(true); // "boolean"
typeof(null); // "object"

引用类型:function是特殊类型,可以直接用typeof来判断是否是function。
typeof([]); // "object"
typeof({}); // "object"
typeof(function(){}); // "function"
typeof总结:

instanceof操作符可以专门用来检测引用类型,判断当前对象是什么类型的对象。
alert({name: "aa"} instanceof Object); // true
alert([1, 2] instanceof Array); // true
alert(function(){} instanceof Function); // true
alert([1, 2] instanceof Object); // true 所有引用类型的值都是Object的实例,因此多带带的判断instanceof Object并不能区分是数组,还是函数等,instanceof应该用来检测真正的对象实例。
alert(13 instanceof Number); // false 使用instanceof检测基本类型的值,始终返回false,因为基本类型不是对象。
new Number(12) instanceof Number; // true
javascript最准确且简便的方法:

参考文献

https://www.zhihu.com/questio...
https://www.cnblogs.com/focus...
https://www.cnblogs.com/telne...
https://www.jianshu.com/p/585...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92453.html

相关文章

  • 深入理解javascript按值传递与按引用传递

    摘要:引用类型参数的传递与引用类型的复制一样,传递的是内存地址。指向一个新的地址,与不再指向同一个地址官方解释来一发中所有函数的参数都是按值传递的。总结很简单,函数参数都是按值传递都是栈内数据的拷贝。 基本类型与引用类型 值类型(基本类型):String,Number,Boolean,Null,Undefined。 引用类型:Array、Object、Function、Date等有多个值...

    hedzr 评论0 收藏0
  • JavaScript深入之参数按值传递

    摘要:深入系列第九篇,除了按值传递引用传递,还有第三种传递方式按共享传递定义在高级程序设计第三版,讲到传递参数中所有函数的参数都是按值传递的。 JavaScript深入系列第九篇,除了按值传递、引用传递,还有第三种传递方式 —— 按共享传递 定义 在《JavaScript高级程序设计》第三版 4.1.3,讲到传递参数: ECMAScript中所有函数的参数都是按值传递的。 什么是按值传递呢?...

    DataPipeline 评论0 收藏0
  • JS中的值是按值传递,还是按引用传递呢?

    摘要:按引用传递时,函数的形参接收实参的隐式引用,而不再是副本。探究值的传递方式的基本类型,是按值传递的。但这样是否说明的对象是按引用传递的呢我们再看下面的例子仍然是并未被修改为如果是按引用传递,修改形参的值,应该影响到实参才对。 最近遇到个有趣的问题:JS中的值是按值传递,还是按引用传递呢? 在分析这个问题之前,我们需了解什么是按值传递(call by value),什么是按引用传递(ca...

    Jochen 评论0 收藏0
  • JS程序

    摘要:设计模式是以面向对象编程为基础的,的面向对象编程和传统的的面向对象编程有些差别,这让我一开始接触的时候感到十分痛苦,但是这只能靠自己慢慢积累慢慢思考。想继续了解设计模式必须要先搞懂面向对象编程,否则只会让你自己更痛苦。 JavaScript 中的构造函数 学习总结。知识只有分享才有存在的意义。 是时候替换你的 for 循环大法了~ 《小分享》JavaScript中数组的那些迭代方法~ ...

    melody_lql 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<