【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

posted @ 2016-12-17 19:42  幻想家~  阅读(373)  评论(0编辑  收藏  举报