二话不说,直接上代码
var a = ?;
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
这道题考查的是对于"=="操作类型转换,首先我们先来看看"="都有哪些特性:
1.= 赋值:变量和值的关联
2.== 比较:如果左右两边的数据类型不一致,则默认转换为一致的(对象==字符串,把对象转换为字符串,剩下的情况(除了null/undefined)一般都是要转换为数字)
3.基本数据类型转换为数字,默认都是隐式调用Number()处理的
4.对象转为数字,需要先转换为字符串(先调用valueOf方法,获取其原始值(基本数据类型基于构造函数创建出来的对象,他们的原始值都是基本值),如果原始值不是基本类型值,则继续调用toString),然后再把字符串转换为数字
5.=== 绝对比较:类型和值都得相同,类型不一样,也不会默认去转(推荐)
那此时我们知道了"=="具有数据类型转换的功能,所以就有了第一种方案
var a = {
i: 0,
// 给当前对象重写“私有”方法valueOf/toString,这样就不会在向原型上找内置的方法
valueOf() {
// this => a
return ++this.i;
}
};
对象可以转换,数组也是对象,所以第二种方案:
var a = [1, 2, 3];
// 让A的私有属性toString等于ARRAY原型上的shift(每次执行都是删除数组第一项,返回的结果是删除的那一项)
a.toString = a.shift;
重头戏来了!
数据劫持
数据劫持(劫持对象中的某个属性): 在每一次获取a值的时候,我们把它劫持到,返回我们需要的值
那我们首先看看数据劫持都有哪些特性
Object.defineProperty(window, 'a', {
get() {
// 在每一次获取window.a的时候被触发执行
// 返回啥值,本次获取的值就是啥
},
set(val) {
// 在每一次给window.a赋值的时候执行
}
});
我们这个例子不需要给a赋值,所以只用get()方法就够了
var i = 0;
Object.defineProperty(window, 'a', {
get() {
return ++i;
}
});
if (a == 1 && a == 2 && a == 3) {
console.log('OK');//OK
}
例2:
let obj = {
2: 3,
3: 4,
length: 2,
push: Array.prototype.push
}
obj.push(1);
obj.push(2);
console.log(obj);
这里面用到了push这个方法,那数组中的push实现的原理是什么呢?
Array.prototype.push:向数组末尾追加新的内容
Array.prototype.push = function push(val) {
// this -> 当前操作的实例 arr
1.向数组(THIS)末尾追加新的内容【数组索引是连续的,所以新增加这一项的索引肯定在原始最大的索引上加1】
// this[this.length] = val;
2.原始数组(THIS)的长度在之前的基础上会自动加1
// this.length++;
3. 返回新增后数组的长度
};
let arr = [10, 20];
let res = arr.push(30);
// res=3 新增数组的长度
所以我们就知道了原题中obj里面的属性都是自己私有后加的
obj.push(1);
相当于是:
- obj[obj.length]=1 =>obj[2]=1
- obj.length++ =>obj.length=3
- return没用
{2:1,3:4,length:3,push:...}
同理
obj.push(2);
- obj[obj.length]=2 =>obj[3]=2
- obj.length++ =>obj.length=4
所以:
console.log(obj); //{2:1,3:2,length:4,push:...}