前言
最近在看前端八股,顺便补充一下js基础,于是简单实现了一些js函数
一、instanceof实现
用途:判断引用类型数据是否为某个数据类型,只能比较引用类型数据,无法比较基本类型,基本类型比较推荐实用typeof
/**
*实现instanceof
*只检测对象,非对象无法检测,全部返回false
*/
function _instanceof(obj, target){
//判断是否对象,或者是否为null
if(typeof obj !== 'object' || obj === null) return false
//获取obj的prototype
let proto = Object.getPrototypeOf(obj)
//obj的prototype存在
while(proto){
//判断是否为target的prototype
if(proto === target.prototype) return true
//不是则在原型链上继续获取prototype
proto = Object.getPrototypeOf(proto)
}
//遍历完原型链还没有返回true 则表示类型不对 返回false
return false
}
// 测试
console.log(_instanceof({}, Object)) // true
console.log(_instanceof([], Array)) // true
let map = new Map()
console.log(_instanceof(map, Map)); //true
二、new实现
/**
* 实现new
* @param {*} constructor 构造
* @param {...any} args 参数列表
* @returns 创建的对象
*/
function _new(constructor, ...args){
const obj = Object.create(constructor.prototype)
//使用apply绑定this 传args类数组对象,
//执行constructor构造函数方法
let res = constructor.apply(obj, args)
//构造函数如果没有返回值,则返回obj,否则返回res
return typeof res === 'object' ? res : obj
}
//测试
function Test(name, age){
this.name = name
this.age = age
}
Test.prototype.say = function(){
console.log(this.name, this.age)
}
Test.prototype.set = function(age){
this.age = age
}
let test = _new(Test, '小陈', 22)
test.say() //小陈 22
test.set(222222)
test.say() //小陈 222222
三、浅拷贝实现
/**
* 实现浅拷贝
* @param {*} obj
* @returns 新对象
*/
function shallowClone(obj){
// 判断是否为空
if(obj === null) return obj
// 判断是否基本数据类型
if(typeof obj !== 'object') return obj
// 为引用类型则创建新对象来存放
const newObj = new obj.constructor()
// 遍历对象
for(let item in obj){
// 判断该对象是否存在该属性,不包括继承属性
if(obj.hasOwnProperty(item)) newObj[item] = obj[item]
}
return newObj
}
// 测试
let obj = {
a: 1,
name: '小陈',
x:{
xx: 222,
y:[1,3,4],
z:{
bb: 1
}
}
}
let newObj = shallowClone(obj)
//修改newObj中引用类型属性,验证浅拷贝
newObj.x.z = 1
console.log(newObj) //{ a: 1, name: '小陈', x: { xx: 222, y: [ 1, 3, 4 ], z: 1 } }
console.log(obj) //{ a: 1, name: '小陈', x: { xx: 222, y: [ 1, 3, 4 ], z: 1 } }
四、深拷贝实现
该实现为基本实现,未解决循环引用问题,解决该问题需要使用weakmap
/**
* 实现基本深拷贝 不能解决循环引用问题
* @param obj 被拷贝的对象
* @retuen 新对象
*/
function deepClone(obj){
// 为null或undefined直接返回
if(obj === null) return obj
// 为Date则创建一个Date返回
if(obj instanceof Date) return new Date(obj)
// 基本类型直接返回
if(typeof obj !== 'object') return obj
// 引用类型才创建一个新对象,并递归拷贝对象里的属性
// 使用new obj.constructor是因为该对象可能是普通对象,也可能是数组,用对象的构造方法可以创建对应的数据类型
const newObj = new obj.constructor()
for(let item in obj){
// 拷贝到新对象中
newObj[item] = deepClone(obj[item])
}
return newObj
}
// 测试
let obj = {
a: 1,
name: '小陈',
sex: '男',
x:[1,2,4,5],
b:{
xx: 'test',
y: 1111
}
}
let newObj = deepClone(obj)
// 修改newObj的值,看看原对象是否被影响,验证深拷贝
newObj.a = 2
console.log(newObj) //{a: 2,name: '小陈',sex: '男',x: [ 1, 2, 4, 5 ],b: { xx: 'test', y: 1111 }}
console.log(obj) //{a: 1,name: '小陈',sex: '男',x: [ 1, 2, 4, 5 ],b: { xx: 'test', y: 1111 }}
总结
都是一些简单实现,该文章是用来记录学习实践,后续会继续更新
如果文中内容或解释有错误,欢迎指正