【JavaScript基础】在写冒泡排序时遇到的JavaScript基础问题:JavaScript的数据类型和变量赋值时的原理
写冒泡排序时,遇到一个问题:
function bubbleSort(arr){ var temp = 0; console.log("传入的数组:"); console.log(arr); for(var i = 0;i<arr.length;i++){ //循环arr.length-1次 console.log("外层第"+i+"次循环===============start"); for(var j = 0;j<arr.length-1;j++){ //循环arr.length-1-1次 if(arr[j]<arr[j+1]){ //倒叙排列数组:如果相邻的两个,前面那个比后面那个小,就互换 temp = arr[j]; // —┐ arr[j] = arr[j+1]; // —├—借助中间变量将数组中的两个值进行互换 arr[j+1] = temp; // —┘ } console.log("内层"+j+"次循环"); console.log(arr); } console.log("外层第"+i+"次循环===============end"); } return arr; }
var array = [2,3,9,5,7,1,8]; var sortArray = bubbleSort(array); console.log("array "+array);//array 9,8,7,5,3,2,1 console.log("sortArray "+sortArray);//sortArray 9,8,7,5,3,2,1 //好奇为什么array也被排序了吗?
看下面的研究:
我首先想到的是,是不是return的问题。难道我脑子里少记了一个return的不知道的关键作用?
先测试一下:
function foo(bar){ bar = 1; return bar; //return 3; } var a = 0; var b = foo(a); console.log(a) //0 console.log(b) //1 //如果return 3 就得到3 //不加return, function foo2(bar2){ bar2 = 1; } var a2 = 0; var b2 = foo2(a2); console.log(a2) //0 console.log(b2) //undefined
return就是用来返回函数值的,它真的没什么特殊的神奇的功效。
其实就是直接删掉return,试一下就知道是不是了,我怎么会怀疑这个。
等等,为什么上面的a不会被修改掉啊,难道跟a是数字有关?
那这里的问题应该就出在数组上。
数组怎么了?关于JavaScript的数据类型和赋值原理的这一块知识,我的脑子里模糊了。
先来段代码试试:
function foo(bar){ bar = [1,2,3,4]; return bar; } var a = [1,2,3]; var b = foo(a); console.log(a) //[1,2,3] console.log(b) //[1,2,3,4] function foo2(bar2){ bar2[0] = 0; return bar2; } var a2 = [1,2,3]; var b2 = foo(a2); console.log(a2) //[0,2,3] console.log(b2) //[0,2,3]
两个函数同样是数组,为什么结果不一样?
上面原因在于数组是引用数据类型
关于js数据类型的研究
js中数据类型分为:
string,number,boolean,[],{},null,undefined
字符串,数字,布尔,数组,对象,null,undefined
null和undefined区别????-------------------------------------undefined:声明变量但未初始化,null,找不到该对象
null==undefined//true
null===undefined//false
上面的数据类型可以分类
原始类型和引用类型
原始类型:undefined,null,boolean,number,string
引用类型:[],{}
在许多语言中,字符串string都被看作引用类型,而非原始类型,因为字符串的长度是可变的,但是js打破了这一传统。
但是,JavaScript拥有动态类型的,也就是说,一个变量可以被赋值成不同的类型。
那么我们接下来就不考虑纠结变量是哪种数据类型了,每个数据类型有怎样怎样了了,我们直接从 变量的值 的角度 来继续思考
在js中,一个变量可以拥有两种类型的值(参考上面数据类型)
原始值和引用值
原始值:存储在栈(stack)中的简单数据段,也就是说,他们的值直接存储在变量访问的位置
引用值:存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。
所以,在为变量赋值时,JavaScript的解释程序必须先判断该值是原始类型还是引用类型。
要实现这一点,JavaScript解释程序则需尝试判断该值是否是JavaScript的原始类型之一。原始类型有哪些上面已经说过了。
如果是原始类型,由于原始类型占据的空间是固定的,所以在内存中,他们被存储在栈中,这样子便于快速查询变量的值。(关于string长度可变看上面)
如果是引用类型,那么它的存储空间将从堆中分配。原因是因为,引用值的大小会改变,所以不能把他们放在栈中,否则会降低变量查询的速度。因此我们就把该对象在堆中的地址放在栈中。地址的大小是固定的,所以对变量性能无任何负面影响。
如图所示:
------------------------------------------------这上面相关知识来源:http://www.w3school.com.cn/js/pro_js_value.asp
------------------------------------------------这下面相关知识来源:https://www.zhihu.com/question/26042362/answer/31903017
所以上面的出现的问题也就好解释了。
可以简化成这样:
var a = [1,2,3]; var b = a; a = [4,5,6]; alert(b); //[1,2,3] var a = [1,2,3]; var b = a; a.pop();//内置函数,删掉数组最后一个 alert(b); //[1,2]
图解就是这样:
就算是调用函数
var b = foo(a)
只要这个函数里面的操作直接操作传入的数组对象本身,那么就是在操作堆中的对象。
就会修改到自身。
只要是没有操作它本身,而是在堆里创建了一个新的对象,然后重新将栈中b的引用地址修改过去。
就不会修改自身。
拓展阅读;https://zhuanlan.zhihu.com/p/24080761