- 考察push方法的运行
<script>
Array.prototype.push=function push(value){
//1.把value放到末尾
this[this.length]=value;
//2.长度累加
this.length++;
};
let arr=[10,20];
arr.push(30);
//==================================
let obj={
2:3,
3:4,
length:2,
push:Array.prototype.push
}
obj.push(1); // obj[2]=1; length:3
obj.push(2); // obj[3]=2; length:4
console.log(obj);
//则obj变为如下:
obj={
2:1,
3:2,
length:4,
push:Array.prototype.push
}
</script>
- 数据类型转换
//比较的时候,两边类型不一样,会默认转为一样的,然后再进行比较(隐式转换)
//对象字符串:把对象转换为字符串
//null==undefined null/undefined和其他任何值都不相等
//剩下的情况都是转换为数字
//-----------
//对象转换为数字,浏览器底层处理如下:
// +首先调取对象中[Symbol.toPrimitive]的这个属性(属性值是函数):获取原始值,如果这个函数不存在
// +继续调用对象的valueOf方法,如果也不存在,或者获取的结果并不是原始值(基本类型值)
// +则继续调用对象的toString方法,先转换为字符串,再把字符串转换为数字。
let obj={};
console.log(obj[Symbol.toPrimitive]); //undefined
let n=10; //字面量方式创建值:基本类型值/原始类型/值类型
let n=new Number(10); //构造函数方式创建值:引用数据类型
console.log(n.valueof()); //10
//基本数据类型值所属类的原型上都有valueof方法,获取其原始值
//Object.prototype.valueOf:此方法获取的结果是引用类型值(不算原始值,原始值一般指的是基本类型值)
//Object.prototype.valueOf.call(10) //得到的结果是new Number(10)
//数组/正则/函数所属类的原型上都没有valueOf,调用的都是Object.prototype.valueOf
//Date.prototype.valueOf:获取日期对象的原始值(距离1970-1-1 00:00:00之间的毫秒差)
console.log(new Date()-10); //1599051256501
console.log(({})-10); //NaN
console.log(new Number(10)+10); //20
例题:a的值为什么,才会 输出ok
// 方案一:利用数据类型转换的机制,我们重写方法实现效果
var a={
value=0,
//valueof/toString
[Symbol.toPrimitive](hint){
//浏览器调取这个方法的时候会传递一个hint:存储当前对象即将转换为什么值
//default:可能转换为数字或者字符串,例如:==比较或者加号运算
//number:一定转换为数字的,例如:减乘除等数学运算中
//string:一定是转换为字符串的,例如:字符串拼接
return ++this.value;
}
}
//隐式调用:a[Symbol.toPrimitive]
if(a==1&&a==2&&a==3){
console.log('OK');
}
//方案二
let a=[1,2,3];
a.toString=a.shift;
if(a==1&&a==2&&a==3){
console.log('OK');
}
//方案三:利用数据劫持 Object.defineProperty / Proxy
//如果a不是全局变量,则再看是否为window 的一个属性...
let i=0;
Object.defineProperty(window,'a',{
get(){
//获取window.a的属性,触发GETTER函数
return ++i;
},
set(){
//window.a=xxx 触发SETTER函数
}
});
if(a==1&&a==2&&a==3){
console.log('OK');
}
- 写toArray函数实现数组的输出
<script>
let utils=(function (){
// toArray:转换为数组的方法
// @params
// 不固定数量,不固定类型
// @return
// [Array] 返回的处理后的新数组
//第一种
// function toArray(...args){
// //ES6剩余运算符接收到的实参本身就放到了数组中
// return args;
// }
//第二种
// function toArray(){
// //arguments获取到的是类数组,需要把他转换为数组
// //return Array.from(arguments); //ES2015
// //return [...arguments]; //es6中的展开运算符
// }
//第三种
function toArray(){
let arr=[];
for(let i=0;i<arguments.length;i++){
arr.push(arguments[i]);
}
return arr;
//直接改写成如下:
//JS中的“鸭子”类型:arguments本身不是数组,但是结构和数组类似(超级类似:数字索引、逐级递增 、length存储集合长度...)
return [].slice.call(arguments);
}
return {
toArray
};
})();
let ary=utils.toArray(10,20,30);
console.log(ary);
ary=utils.toArray('A',10,20,30);
console.log(ary);
</script>
slice
<script>
//重写内置的slice,实现浅克隆的效果
function slice(){
//this->ary
let arr=[];
for(let i=0;i<this.length;i++){
arr.push[this[i]];
}
return arr;
}
let ary=[10,20,30];
console.log(ary.slice()); //slice()或者slice(0)都是实现数组的浅克隆
</script>
- 类数组(arguments/NodeList/HTMLCollection/JQ集合…)
<script>
let obj={
0:10,
1:20,
2:30,
length:3
};
//数组中的其他方法一样可以被借用
Array.prototype.forEach.call(obj,(item,index)=>{
console.log(item,index);
});
//直接写成如下也可以
console.log(Array.from(obj));
</script>