1.手写一个简单渲染器,将虚拟dom渲染为真实dom
const vnode = {
tag: 'div',
props: {
onclick: () => alert('hello')
},
children: 'click me'
}
// 手写一个渲染器,用来渲染上面的代码,把上面的代码渲染为真实dom
function renderer(vnode, container) {
// 使用vnode.tag作为标签名创建DOM元素
const el = document.createElement(vnode.tag)
// 遍历vnode.props属性,将属性和事件添加到dom元素中
for (const key in vnode.props) {
// 如果开头以on结尾的key,说明是事件
if (/^on/.test(key)) {
el.addEventListener(
//
key.substr(2).toLowerCase(), // 事件名称 onClick ---> click
vnode.props[key] // 事件处理函数
)
}
}
if (typeof vnode.children === 'string'){
// 如果是字符串,说明它是元素的文本子节点
el.appendChild(document.createTextNode(vnode.children))
}else if(Array.isArray(vnode.children)){
vnode.children.forEach(v=>render(v,el))
}
container.appendChild(el)
}
// body作为挂载点
renderer(vnode,document.body)
2.手写ajax
// 手写ajax
const SERVER_URL = "/server"
let xhr = new XMLHttpRequest();
// 创建http请求 参数(请求的方法,请求的地址,是否异步和用户的认证信息)
xhr.open("GET",SERVER_URL, true);
// 设置状态监听函数
xhr.onreadystatechange = function(){
if(this.readyState !== 4 ) return;
// 当请求成功时
if(this.status === 200){
handle(this.response)
}else{
console.log(this.statusText);
}
};
// 设置请求失败时的监听函数
xhr.onerror = function(){
console.log(this.statusText);
}
// 设置请求投信息
xhr.responseType = "json";
xhr.setRequestHeader("Accept","application/json")
// 发送http请求
xhr.send(null)
3.用promise二次封装ajax
function getJSON(url){
// 创建一个promise对象
let promise = new Promise((res,rej)=>{
let xhr = new XMLHttpRequest()
// 创建一个http请求
xhr.open("GET",url,true)
xhr.onreadystatechange=function(){
if(this.readyState !== 4) return;
// 当请求成功或者失败时,改变promise状态
if(this.status === 200 ){
res(this.response)
}else{
rej(new Error(this.statusText));
}
};
// 设置错误监听函数
xhr.onerror = function(){
rej(new Error(this.statusText))
};
// 设置请求头信息
XMLHttpRequest.setRequestHeader("Accept","application/json");
// 发送http请求
xhr.send(null);
});
return promise
}
4.实现浅拷贝
- **浅拷贝:**浅拷贝是将一个对象的属性复制到另一个值中,如果对象中属性的值为引用类型的时候,把这个引用类型的地址复制给对象。
- **深拷贝:**深拷贝是将一个对象的属性复制到另一个值中,如果对象中属性的值为引用类型的时候,新建一个引用类型然后将对象中的值复制给他,而不是复制原来值得地址。
(1)、Object.assign(target,source…)
let a = {a:1}
let b = {b:2}
let c = {c:3}
let d = Object.assign(a,b,c)
console.log(a); // { a: 1, b: 2, c: 3 }
console.log(d); // { a: 1, b: 2, c: 3 }
(2)、扩展运算符
let obj1 = {a:1,c:{b:1}}
let obj2 = {...obj1}
console.log(obj1); // { a: 1, c: { b: 1 } }
console.log(obj2); // { a: 1, c: { b: 1 } }
obj1.a = 2
console.log(obj1); // { a: 2, c: { b: 1 } }
console.log(obj2); // { a: 1, c: { b: 1 } }
obj1.c.b = 2
console.log(obj1); // { a: 2, c: { b: 2 } }
console.log(obj2); // { a: 1, c: { b: 2 } }
(3)、Array.prototype.splice()
let arr1 = [1,2,3]
let arr2 = arr1.slice()
console.log(arr1); // [1,2,3]
console.log(arr2); // [1,2,3]
(4)、手写浅拷贝
// 浅拷贝的实现;
function shallowCopy(object) {
// 只拷贝对象
if (!object || typeof object !== "object") return;
// 根据 object 的类型判断是新建一个数组还是对象
let newObject = Array.isArray(object) ? [] : {};
// 遍历 object,并且判断是 object 的属性才拷贝
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] = object[key];
}
}
return newObject;
}
5.实现深拷贝
(1)、JSON.parse(JSON.stringify())
let a = {a:1,b:{c:1}}
let b = JSON.parse(JSON.stringify(a))
a.b.c= 2
console.log(a); // { a: 1, b: { c: 2 } }
console.log(b); // { a: 1, b: { c: 1 } }
(2)、lodash
let _ = require('lodash')
let a = { a: 1, b: { c: 2 } }
let b = _.cloneDeep(a)
a.b.c=3
console.log(a); // { a: 1, b: { c: 3 } }
console.log(b); // { a: 1, b: { c: 2 } }
(3)、手写深拷贝
function deepCopy(object){
if(!object || typeof object !== "object") return ;
let newObj = Array.isArray(object)?[]:{}
for (const key in object) {
if(object.hasOwnProperty(key)){
newObj[key] = typeof object[key] === "object"?deepCopy(object[key]):object[key]
}
}
return newObj
}
6.单例模式
实现Storage,使得该对象为单例,基于 localStorage 进行封装。实现方法 setItem(key,value) 和 getItem(key)。
class Storage {
static getInstance(){
// 判断是否 new 过一个实例
if(!Storage.instance){
Storage.instance = new Storage()
}
return Storage.instance
}
setItem(key,value){
return localStorage.setItem(key,value)
}
getItem(key){
return localStorage.getItem(key,value)
}
}
const Storage1 = new Storage.getInstance()
const Storage2 = new Storage.getInstance()
Storage1.setItem('name','王杰')
Storage1.getItem('name')
Storage2.getItem('name')
// 返回true
Storage1 === Storage2
7.列表转树
// 列转树算法
transTree(data) {
let result = []
let map = {}
if (!Array.isArray(data)) {//验证data是不是数组类型
return []
}
data.forEach(item => {//建立每个数组元素id和该对象的关系
map[item.ttId] = item //这里可以理解为浅拷贝,共享引用
})
data.forEach(item => {
let parent = map[item.parentTtId] //找到data中每一项item的爸爸
if (parent) {//说明元素有爸爸,把元素放在爸爸的children下面
(parent.children || (parent.children = [])).push(item)
} else {//说明元素没有爸爸,是根节点,把节点push到最终结果中
result.push(item) //item是对象的引用
}
})
return result //数组里的对象和data是共享的
},