我们都知道,JS中变量的赋值有两种方式,最近在折腾自己写的标签栏插件,碰到了很多平时没注意的问题。正好,那边处理清楚了,稍微整理一下关于引用与复制相关知识,可能会不定期增加新碰到的问题,有错误希望看到的人指出,避免传播不正确的知识。
先大致分一下类,引用类型:Object以及其旗下的Array,Date,RegExp,Function;基本包装类型:Boolean,number,String。
在赋值与传递参数的时候,引用类型传递的是指针,基本包装类型是复制新值传递。常见的情况我就不啰嗦了,一下主要是一些碰到过的容易理解出错的情况,以及探究后得出的个人结论。
修改指针变量不一定会影响到引用对象
可能一下不太好理解这个,来点简单暴力的demo就好说明问题了。
var arr1 = [1, 2, 3], arr2 = arr1; arr2 = [4, 5, 6]; console.log(arr1); console.log(arr2);
这个demo比较简单,结果是:arr1为[1, 2, 3] arr2为[4, 5, 6]
为什么修改arr2后arr1没有改变,arr2 = [4, 5, 6]
修改的是arr2这个指针变量的指向,并没有碰到原引用的数组。
下面这种情况则会修改到原对象。
var arr1 = [1, 2, 3], arr2 = arr1; arr2.pop(); console.log(arr1); console.log(arr2);
此时的结果为: arr1 arr2都等于[1, 2],arr2.pop()
相当于执行[1, 2, 3].pop(),因此arr2引用的原匿名对象被修改了。
因此在操作引用类型的时候,要注意是否修改的是原对象。来一个稍微啰嗦有点的demo:
var arr1 = [1, 2, 3], arr2 = arr1; function test (a) { console.log(a); a = [4, 5, 6]; console.log(a); } test(arr2); console.log(arr1); console.log(arr2);
上面的输出结果根据之前的测试应该是
var arr1 = [1, 2, 3], arr2 = arr1; function test (a) { console.log(a); // [1, 2, 3] a = [4, 5, 6]; console.log(a); // [4, 5, 6] } test(arr2); console.log(arr1); // [1, 2, 3] console.log(arr2); // [1, 2 ,3]
因为在传递arr2给test的时候,相当于执行了a = arr2
因此情况跟第一个demo一样了。同理,将a=[4, 5, 6]
改为a.pop()
,那么结果如同第二个demo。
来一个函数自己修改自己的demo:
var test = function () { var a = 1; test = function () { var b = 3; } }; test(); console.log(test);
此时的test内部为var b = 3;
这种方法有个高大上叫法叫惰性载入,具体我就不啰嗦了,可以百度一下或者谷歌两下。利用的就是函数本身也是引用类型的特点。
下面的这个demo是引用类型中引用类型:
var obj1 = { arr: [1, 2, 3] }, obj2 = obj1; obj2.arr = [4, 5, 6]; console.log(obj1);
输出结果中,obj1被修改了,不难理解执行obj2.arr = [4, 5, 6]
时,相当于执行obj1.arr = [4, 5, 6]
,直接修改了原对象。因此采用简单的赋值操作得不到一个对象的拷贝。取得拷贝的话可以用for(key in object)
的方式遍历对象进行拷贝。
至于原始类型字符串数字之类的基本类型就不多写了,那些都是复制操作,获得的是一个新值。
欢迎纰漏。