首页 > 数组和严格等于“===”以及valueOf()相关问题

数组和严格等于“===”以及valueOf()相关问题

(function(){
var arr=[1,2,3],
    str="1,2,3";
alert(arr.join(",")===arr.toString()&&arr.toString()==="1,2,3"); //true
alert(str.valueOf()===str&&str.valueOf()==="1,2,3");     //true
var a=arr.valueOf();     //[1,2,3]
alert(a===[1,2,3]||arr===[1,2,3]);  //false
})();

想问下最后一个alert为什么不是true?调试了好几遍一直都是false,还想请问一下valueOf()这个方法具体的针对不同对象返回值是什么,因为我自己做了试验然后跟网上搜到的一些结果不一样。


建议看看js数据类型,数组是不能进行全等(===)比较的。


Javascript不能直接用=====比较数组相等。你可以试试这个,能得出true我把电脑吃了:

alert([1, 2] == [1, 2]);
alert([1, 2] === [1, 2]);

解决这个问题,你需要自己写数组的比较函数。(先比length,然后挨个比就行了)

或者你可以试试第三方库。例如非常轻量的Underscore.js: (可通过七牛等CDN使用)

alert(_.isEqual([1, 2], [1, 2])); // true
alert(_.isEqual([1, 2], []));     // false

valueOf()那个,别看太多网上的文章,会晕的,直接来点权威解释呀。

用Google搜JavaScript valueOf() site:www.w3schools.com,能查到所有的valueOf()方法,包含Boolean,Array,String,Date和Number的,试验是准确的,包你满意。


关于 === 操作符,我就简单点解释一下吧


先说一下 JavaScript 中的“值”与“变量”实际是什么关系
在 JavaScript 中,每个“值”都是存放在内存中某个特定位置的一块数据
我们给变量赋值,实际就是:把给定的值放到内存中的一个位置,然后给他起一个名字(也就是变量名)

你可以想象,内存是一个大仓库,里面有很多货品。给变量赋值就是把一个新的货品放进仓库,然后给它挂一个标签,这个标签就是变量名。以后操作变量时,系统就根据变量名(标签)确定你要操作的到底是哪一个货品。

那么,一个货品只能有一个标签吗?
不是的,一个货品可以挂多个标签。
例如我们执行 a = some_value; b = a; 时,就是把标签 b,挂到标签 a 对应的货品上。


接下来就谈到 === 操作符了,这个操作符实际就是看两个标签是不是都挂到了同一个商品上。
它不管这两个货品是不是一样。例如你拿两个完全一样的苹果给它比较,它也是返回 false。
因此, a = [1,2,3]; b = a; a === b 返回 true,而 a = [1,2,3]; b = [1,2,3]; a === b 返回 false。
因为在第二段代码中, a 和 b 对应的已经是两个商品了。


那为什么 a = 1; b = 1; a === b 返回 true 捏?
这个事情涉及到 JavaScript 的底层实现。

JavaScript 中的数据类型分为两种:基本类型 和 引用类型
数字、字符串、true、false、null、undefined 这些是基本类型,其他的都是引用类型(Array, Object...)。
你可以想象基本类型是苹果、剪刀等等普通货品;
引用类型是箱子,瓶子等等本身也是容器的物品,这类货品本身也可以存放其他货品。

JavaScript 中为了提高效率,减少资源占用,进行了一些优化。

当你把基本类型的值赋值给变量时,它不会傻傻的每次都重新创建一次,而是直接把新的标签挂到原有的值上面。 例如: a = 苹果; b = 苹果; JavaScript 不会真的拿两个苹果放进仓库,而是会先看仓库里是不是已经有苹果了,如果有就直接把标签挂上去。因此,a 和 b 都被挂到了同一个货品上。

而对于引用类型,因为其特殊性,就没法这样做了(理由稍后再说)。JavaScript 只好每次赋值时都拿一个新的货品放进仓库。因此,a = [1,2,3]; b = [1,2,3]; ,a 和 b 被分别挂在两个箱子上了。

这也就是 === 对于字符串间的比较能返回 true,而对于数组间的比较会返回 false 的原因


好了,最后来解释下引用类型的值为什么每次赋值都非得重新创建一次

JavaScript 中,基本类型的值是“不可变”的,引用类型的值是“可变的”

例如一个字符串,a = "abc",除了给 a 赋一个新值,我们没有其他办法对 a 对应的字符串进行任何改变。 也就是说,我们只能是把 a 这个标签挂到另一个货物上,来让 a 的值发生变化,但是我们没法直接让货物发生改变。 a = "abc",我们没有办法通过某个方法,或者某个操作符,让 "abc" 变成 "Abc"

但是引用类型就不一样了,引用类型的值就是箱子,它里面是可以装其他值的。 我们虽然不能更改箱子,但我们可以往里面放东西,或者取出东西。 a = [1,2,3]; a.push(4); //a 就变成了 [1,2,3,4] 我们没有重新给 a 赋值,但是 a 的值已经发生变化了。

如果 JavaScript 对待引用类型的值也像对待基本类型一样,每次赋值都把标签挂在已有的商品上,就会出现这样的情况:

// 注意:真实世界里不会出现这样的事
a = [];
b = [];
a[0] = 'haha';
alert(b[0]);   // 输出 haha

a = {'name': null}
b = {'name': null}
a.name = 'David'
alert(b.name)  // David

只要程序中任意两个地方碰巧创建了键值对相同的对象,或元素相同的数组(你自己可能都完全不知道),他们就会永远保持一致。 基于这样的原因,JavaScript 无法对引用类型进行与基本类型相同的优化。


就是这些了,是不是很简单哪

【热门文章】
【热门文章】