浅拷贝
let obj = { a: 1, b: 2 }
Object.assign({},obj) // 它包含了原始对象种Symbol属性的处理,for in就没有
Object.keys(obj) 拿不到symbol
如果想要完整的 需要搭配 Object.getOwnPropertySymbols(obj) // 专门拿Symbols属性
Object.getOwnpropertySymbols(obj) 专门拿symbol
function shallowClone(obj){
let type = Object.prototype.toString.call(obj)
let contor = obj.constructor;
if(type === '[object Symbol]' || type === '[object Bigint]') return Object(obj);
if(type === '[object RegExp]' || type === '[object Date]') return new contor(obj)
if(type === '[object Error]') return new contor(obj.message)
if(type === '[object Function]') {
return function(){
return obj.call(this,...arguments)
}
}
if(type === '[object Array]' || type === '[object Object]'){
// 这样的话包含Symbol属性,
return type === '[object Array]' ? [...obj] : {...obj}
}
return obj
}
深拷贝
function deepClone(obj,cache = new Set()){
let type = Object.prototype.toString.call(obj);
let contor = obj.constructor;
// 如果不是数组和对象的话直接copy过去
if(type !== '[object Array]' || type !== '[object Object]') return shallowClone(obj);
// 为了防止无限套娃
if(cache.has(obj)) return obj;
cache.add(obj)
let keys = [
...Object.keys(obj),
...Object.getOwnPropertySymbols(obj)
]
let result = new contor();
keys.forEach(itm => {
result[key] = deepClone(obj[key], cache)
})
return result
}
类数组转化为数组
- Array.prototype.slice.call(arguments)
- Array.from(document.querySelectorAll('div'))
- [...document.querySelectorAll('div')]
- Array.prototype.concat.apply([],arguments)
- [].forEach.call(arguments,(itm) => { console.log(itm) })
数组方法
forEach
MDN: developer.mozilla.org/zh-CN/docs/…
Array.prototype.forEach = function(callback,context){
let self = this;
i = 0;
len = self.length;
context = context === null ? window : context;
for(;i<len;i++){
typeof callback === 'function' ? callback.call(context,self[i]) : null
}
}
for in
用for in的时候,最好配合 obj.hasOwnProper辨别是否是obj的私有属性
性能比较差,因为他会把所有的可枚举属性全部迭代一遍(包括原型链)
for of
for of原理是按照迭代器规范遍历Symbol.iterator来遍历的,迭代器就是返回一个对象,这个对象包含next方法,而next方法也返回一个对象,有两个属性,一个是 value:值,一个是 done:是否遍历完成
例如
let arr = [1,2,3,4,5]
for(let key of arr){
}
等价于
obj[Symbol.iterator] = function(){
let self = this;
idx = 0;
return {
// 包含next方法,执行它
// done:false or true 完成 or 未完成
// value: 每次值
next(){
// 最终大于最大索引的话
if(idx > self.length - 1){
return {
done: true,
value: undefined
}
}
return {
done: false,
value: self[idx++]
}
}
}
}
// let itor = arr[Symbol.iterator]()
// itor.next()
如何将对象可以通过for of遍历呢
let ab = {
name: '刷',
age: '18'
}
function createSymbolIterator(obj){
let arr = Object.entries(obj);
let idx = 0;
return {
next(){
if(idx > self.length - 1){
return {
done: true,
value: undefined
}
}
return {
done: false,
value: arr[idx++]
}
}
}
}
ab[Symbol.iterator] = function(){
return createSymbolIterator(ab)
}
for(let key of ab){
console.log(key)
}
实现call
eval方法:developer.mozilla.org/zh-CN/docs/…
Function.prototype.call_ = function (obj) {
//判断是否为null或者undefined,同时考虑传递参数不是对象情况
// 目的是为了防止报错
obj = obj ? Object(obj) : window;
let args = [];
// 注意i从1开始
let len = arguments.length;
for (var i = 1, i < len; i++) {
args.push("arguments[" + i + "]");
};
obj.fn = this; // 此时this就是函数fn
eval("obj.fn(" + args + ")"); // 执行fn
delete obj.fn; //删除fn
};
实现bind
Function.prototype.bind=function (context,...params){
let self = this;
return function proxy(args){
self.apply(context,params.concat(args))
}
}
用setTimeout实现setInterval
难点:涉及到setTimeout多次更新后的值怎么保存
const utils = (
function () {
let interVal = 0;
let interObj = {};
var _setInterval = function (fn,t){
var newInterVal = ++interVal;
function next(){
interObj[newInterVal] = setTimeout(() => {
fn();
next();
},t)
}
next();
return newInterVal;
}
var _clearInterval = function (id){
clearTimeout(interObj[id])
}
return {setInterval: _setInterval,clearInterval: _clearInterval}
}
)()