1-事件委托
let ul = document.querySelector("ul")
console.log(ul)
ul.onclick = function (e) {
//当点击某"li"标签时,该标签内容拼接"."符号。
//e.target双向绑定
console.log(e.target)
e.target.innerHTML += "."
}
2-数组去重
//数组去重
const _deleteRepeat = array => {
// 补全代码
// let set = new Set(array)
// console.log(set)
// return Array.from(new Set(array))
return [...new Set(array)]
}
console.log(_deleteRepeat([-1, 1, 2, 2]))
// [-1,1,2]
3-将数组中的数字小到大排序后返回(快速排序)
快速排序的思想:
const _quickSort = array => {
// 补全代码
//递归实现快速排序
let len = array.length
if (len <= 1) return array
// //
let mid = Math.floor(len / 2)//数组长度的一半
//splice(start:number,deletenum:number),得到的是数组,删除元素,会改变原数组
// slice(start:number,end:number),得到的是数组,不会改变原数组
// console.log(array.splice(mid, 1)[0])
// console.log(array.slice(mid, mid + 1))
let left = [], right = []
let midValue = array.splice(mid, 1)[0]
for (let a of array) {
console.log(a)
a < midValue ? left.push(a) : right.push(a)
}
// console.log(left, "y", right)
return _quickSort(left).concat(midValue,_quickSort(right))
}
console.log(_quickSort([0, -1, 1, -2, 2]))
// [-2,-1,0,1,2]
4-全排列
以数组的形式返回字符串参数的所有排列组合。
注意:
- 字符串参数中的字符无重复且仅包含小写字母
- 返回的排列组合数组不区分顺序
5-实现Array.map
相同功能的_map
函数
//为Array类添加一个_map函数
//本身操作的就是调用函数的数组,函数传入的参数是对数组修改的函数
//箭头函数和普通函数:箭头函数中this是window,普通函数this才能得到调用的数组本身
//map会修改数组本身吗?不会
//fn函数处理的是数组的每个元素
Array.prototype._map = function (fn) {
//console.log(this)
let res = []
for (let a of this) {
res.push(fn(a))
}
return res
}
console.log([1, 2]._map(i => i * 2))
6-实现Array.filter
//[1,2]._filter(i => i>1)
//filter会改变原数组吗?不会
Array.prototype._filter = function (fn) {
let res = []
for (let a of this) {
if (fn(a))
res.push(a)
}
return res
}
console.log([1, 2]._filter(i => i > 1))//[2]
7-实现Array.reduce
//reduce计算数组元素的总和,传入两个参数:第一个参数回调函数,第二个initValue
//对于空数组不执行回调函数
//回调函数的参数
//参数:total初始值或是计算结束之后的返回值;currentValue当前元素(item)
//currentIndex:非必须(index),arr:调用函数的数组对象(this)
//改变原数组吗?不
Array.prototype._reduce = function (fn) {
// console.log(arguments)
let sum = arguments[1] ? arguments[1] : 0;
// forEach可以直接遍历item,index
this.forEach((item, index) => {
sum = fn(sum, item, index, this)
})
return sum
}
console.log([1, 2, 3]._reduce((left, right) => left + right))
8-实现对象的浅拷贝Object.assign
const _shallowClone = target => {
// // 参数可能包含函数、正则、日期、ES6新对象
// //浅拷贝:基本数据类型直接拷贝,引用数据类型只拷贝一层
// //引用数据类型包括
// //null、undefined
// //日期,正则,
//对象数组
if (target === null || typeof target === "undefined"||typeof target !== "object")
return target
let type = Object.prototype.toString.call(target)
if (type == "[Object Date]" || type == "[Object RegExp]" || type == "[Object Function]")
return target;
let res = type = "[Object Array]" ? [] : {}
//Object.keys(target)可以获取target自身的所有的可枚举属性,target是数组对象,得到的是下标
Object.keys(target).forEach((item, index) => {
console.log(item, "y", target[item])
res[item] = target[item]
})
return res
}
let arr = ["q", "w", "e"]
// let arr = {
// name: "yyy",
// age: 20
// }
console.log(_shallowClone(arr))
9-实现简单深拷贝,参数类型以及参数中的属性类型都只有基本数据类型,数组和对象三种类型,不需要考虑循环引用
function checkType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
const _sampleDeepClone = target => {
// 补全代码
//无需考虑循环引用的问题
//参数对象和参数对象的每个数据项的数据类型范围仅在数组、普通对象({})、基本数据类型中]
// [Object Array]
//使用递归实现深拷贝
const type = checkType(target)
let newTarget = type == "Array" ? [] : {}
//Object.keys遍历对象自身可枚举属性,for in遍历对象以及原型链上的可枚举属性
//如果是数组或对象类型接着向上递归,否则直接返回被newTarget[prop]接收
if (type == "Array" || type == "Object") {
for (let prop in target) {
//target.hasOwnProperty(prop)保证一层层遍历
// newTarget[prop]=target.hasOwnProperty(prop)?target[prop]:_sampleDeepClone(prop)
if (target.hasOwnProperty(prop)) {
console.log("prop", prop, "target[prop]", target[prop])
newTarget[prop] = _sampleDeepClone(target[prop])
}
}
return newTarget
} else {
return target
}
}
let arr = {
name: "yyy",
age: 21,
obj: {
name: "syc",
age: 70,
obj2: {
play: "good"
}
}
}
console.log(_sampleDeepClone(arr))
10-复杂深拷贝,
循环引用:一个对象包含对另一个对象的引用,而另一个对象也包含对第一个对象的引用。解决循环引用需要记录已访问属性或者使用弱引用。
使用 new WeakMap() 初始化一个对象 memo 作为记录表,以确保不会无限制地复制相同的对象。如果当前的 memo 已经注册过该对象,则返回 memo 中的新的副本;否则,就新建一个数组或者对象,进行递归复制,同时在 memo 中记录原文件及其副本。
function checkType(param) {
return Object.prototype.toString.call(param).slice(8, -1)
}
const _completeDeepClone = (target, map = new Map()) => {
// 补全代码
//需要考虑函数、正则、日期、ES6新对象
//考虑循环引用
if (target === null || typeof target !== "object") return target
//函数,正则,日期
//如果是es6新对象,函数,正则,日期,直接返回参数对象对应的构造函数生成的实例对象
const type = checkType(target)
if (type == "Function") return new Function(target)
if (type == "Date") return new Date(target.getTime())
if (type == "RegExp") return new RegExp(target)
if(type=="Set")return new Set(target)
if(type=="Map")return new Map(target)
//
const constructor=target.constructor
// const constructor = target.constructor
// if(/^(Function|RegExp|Date|Map|Set)$/i.test(constructor.name)) return new constructor(target)
if(/^(Function|Date|RegExp|Set|Map)$/i.test(constructor.name))return new constructor(target)
//数组,对象
//map,set
//如果出现循环引用,直接返回引用
//如果从map中可以获取当前参数对象,循环引用,直接返回;如果不能获取,将当前参数对象加入map标记
if (map.has(target)) return map.get(target)
else map.set(target, true)
//
let newTarget = type === "Array" ? [] : {}
//前面已经判断过非[]{}的直接返回了
for (let prop in target) {
if (target.hasOwnProperty(prop))
newTarget[prop] = _completeDeepClone(target[prop], map)
}
}
// let a = new Map()
// a.set("name", "yyy")
// console.log(checkType(a))
const _completeDeepClone = (target, map = new Map()) => {
//基本数据类型,null,undefined
if (target === null || typeof target !== "object") return target
//解决循环引用
if (map.has(target)) return map.get(target)
//函数、正则、日期、ES6新对象
const constructor = target.constructor
console.log(constructor.name)
console.log("ok", /^(Function|Date|RegExp|Map|Set)$/ig.test(constructor.name))
let newTarget;
if (/^(Function|Date|RegExp|Map|Set)$/ig.test(constructor.name))
//根据参数对象对应的构造函数得到实例对象
newTarget = new constructor(target)
map.set(target, newTarget)
//Map,Set,Symbol
//Array.from处理可迭代对象
if (constructor == "Map") {
Array.from(target, (key, val) => { newTarget.set(_completeDeepClone(key, map), _completeDeepClone(val, map)) })
} else if (constructor == "Set") {
Array.from(target, key => { newTarget.add(_completeDeepClone(key, map)) })
} else if (constructor == "Symbol") {
newTarget = Symbol(target.description)
} else {
//数组和对象
// 然而,如果输入对象非常大或太嵌套,则可能导致堆栈溢出。
newTarget = (Array.isArray(target)) ? [] : {}
for (let prop in target) {
if (target.hasOwnProperty(prop))
newTarget[prop] = _completeDeepClone(target[prop], map)
}
}
return newTarget
}
11-发布订阅模式
- 同一名称事件可能有多个不同的执行函数
- 通过"on"函数添加事件
- 通过"emit"函数触发事件
class EventEmitter {
// 补全代码
//发布-订阅模式是一种软件架构模式,多个组件将事件、消息传递给主题,中心类
constructor(){
this.events={}//使用events对象存储事件名称和事件处理函数
}
on(eventName,func){
//eventName在事件对象中是否存在
//key是eventName:String,value是存放事件处理函数的数组
if(!this.events[eventName])
this.events[eventName]=[]
this.events[eventName].push(func)
}
emit(eventName,args){
//执行事件处理函数
const event=this.events[eventName]
if(event){
event.forEach((func)=>{
//apply() 来调用与事件名称关联的每个函数,
//并将提供的参数作为一个参数数组传递进去,以确保每个函数都会接收到这些参数并执行相应的操作。
func.apply(null,args)//
})
}
}
12-观察者模式(有误)
请补全JavaScript代码,完成"Observer"、"Observerd"类实现观察者模式。要求如下:
- 被观察者构造函数需要包含"name"属性和"state"属性且"state"初始值为"走路"
- 被观察者创建"setObserver"函数用于保存观察者们
- 被观察者创建"setState"函数用于设置该观察者"state"并且通知所有观察者
- 观察者创建"update"函数用于被观察者进行消息通知,该函数需要打印(console.log)数据,数据格式为:小明正在走路。其中"小明"为被观察者的"name"属性,"走路"为被观察者的"state"属性
注意: - "Observer"为观察者,"Observerd"为被观察者
class Observerd {
//主题对象,被观察者
constructor(name) {
this.name = name
this.state = "走路"
this.observers = []//存储观察这个被观察者的观察者对象们
}
//保存观察者们
setObserver(observer) {
// if (!this.observers[observer])
this.observers.push(observer)
}
// 设置该观察者state并通知其他所有观察者
setState(state) {
this.state = state
//通知观察者
//this.notifyObservers()
for(let observer of this.observers){
observer.update(this)
}
}
// this.observers.forEach(item=>{
// //箭头函数无法保证this是当前实例化的的被观察者对象
// item.update(this)
// })
}
}
class Observer {
//被观察者的消息通知
update(observered) {
console.log(observered.name,"正在",observered.state)
}
}
13、Object.create
只能改变新创建对象的属性,无法改变继承的原型对象上的属性
const person = { name: "yyy" }
const student = Object.create(person)
student.age = 21
delete student.person
console.log(person.name)//yyy
console.log(student.name)//yyy
delete student.age
console.log(student.age)//undefined