首先来个题目:
是否有个变量 a ,满足下面条件
console.log(a == 1 && a == 2 && a == 3) 输出为 true
第一眼是不是很懵,What ? 怎么有这种变量,看官姥爷们先别急,我们一步一步来
基本类型
首先我们了解一下 js 中的六种数据类型:
- stiring
- number
- boolean
- null
- undefined
- object
注意:简单数据类型 ( string, boolean, number, null 和 undefined ) 本身不是对象。所以 js 中 ”万物皆对象“ 显然是错误的。
null 有时被认为是对象类型 ( typeof null 输出为 "object" ),其实是语言的一个 bug。原理是: 所有对象在底层都表示为二进制,在 js 中,二进制前三位都为 0 会被判断为 object 类型,null 的二进制表示全为 0 ,所以执行 typeof 时返回 object。
包装类型
js 中有三种包装类型:
- Boolean
- Number
- String
包装类型和基本类型有什么不同呢?不急,为了让你印象深刻,先思考下面代码是否可以执行
'1'.toString();
答案是会的。'1' 是简单数据类型 string。 简单数据类型是没有方法的,为什么又可以调用 toString 方法呢?因为 js 做了隐式转换,将简单数据类型 (string) 转为包装类型 (String), var s = new String("1"),再调用该对象上的 toString 方法。
继续思考以下代码:
var s1 = "some text";
console.log(s1.toString());
s1.color = "read";
console.log(s1.color); // 输出什么?
答案是 undefined。虽然 js 隐式创建了一个 String 对象,然后 s1.color = "read" 动态给对象设置属性。但是这个对象只存在了一瞬间,之后就会执行 s1 = null; 这也是包装对象和引用类型创建的对象的区别,引用类型创建的对象在执行的期间一直在内存中。
那么我们怎么才能给基本类型添加方法或者属性呢? 我们可以在基本包装对象的原型下面添加,每个对象都有原型。
var s1 = "some text";
String.prototype.last= function(){
return(this.length);
};
console.log(str.last());
隐式类型转换
- 当一侧操作数为String类型, 会优先将另一侧转换为字符串类型
console.log(1 + '2') // 12
- 当一侧操作数为Number类型 另一侧会转为Number类型
console.log(1 + true); // 2
- 当一侧为Number类型, 另一侧为引用类型
console.log(1 + {toString: function() {return 'ddd'}}); //1ddd
对象提供了value 类型转化
```
console.log(3*{valueOf: function() { return 5}}); // 15
```
- 当两侧都为对象时
console.log({} + {}); // [object Object][object Object]
进阶
思考以下代码:
console.log([] == ![]); // true or false
答案是true。首先 !运算符优先级高于 == ,所以首先计算 ![], 此处进行了隐式类型转换(Boolean)=> false。同时 == 也会触发类型转换(Number)。 所以上述代码会演变为下面的代码
console.log(Number([])==Number(false));
给个思考代码:欢迎评论区留言讨论
console.log(Boolean([]) == Boolean(![]));
填坑
思考:每次需要我们使得 a 的值依次等于 1, 2, 3 ;所以我们可以定义一个对象,每次调用的时候都返回一个不同的值。根据这个思路,我们可以想到该对象中需要一个变量和一个使得该变量自加的一个返回值。代码如下
版本一
const a = {
value : 1,
valueOf:function(){return this.value++}
}
console.log(a == 1 && a == 2 && a == 3)
版本二
const a = {
value: [3,2,1],
valueOf: function() { return this.value.pop()}
}
console.log(a == 1 && a == 2 && a == 3)
还有小伙伴提供了另外一种思路,该思路很巧妙,欢迎小伙伴们一起思考讨论
var a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);