原生方法实现
大约 4 分钟
原生方法实现
instance
function myInstanceOf(obj, origin) {
if (typeof obj != 'object' || obj == null) return false
while (obj) {
if (obj._proto_ == origin.prototype) {
return true
}
obj = obj._proto_
}
return false
}
New
function myNew(Fun) {
let obj = {}
obj._proto_ = Fun.prototype
let res = Fun.apply(obj, Array.prototype.slice.call(arguments, 1))
return typeof res == 'object' ? res : obj
}
call
function myCall(context, ...args) {
context = context || window // context = (typeof context === 'object' ? context : window)
// 防止覆盖掉原有属性
let key = Symbol()
// 这里的this为需要执行的方法
context[key] = this
let res = context[key](...args)
delete context[key]
return res
}
bind
function myBind(context, args) {
context = context || window // context = (typeof context === 'object' ? context : window)
return (...args) => {
this.call(context, ...args)
}
}
原型链继承
function Parent() {
this.name = 'tom'
}
Parent.prototype.sayName = function () {
console.log(this.name)
}
function Child() {}
Child.prototype = new Parent()
构造函数继承
function Parent(name) {
this.name = name
this.sayName = function () {
console.log(this.name)
}
}
function Child(name) {
Parent.call(this, name)
}
组合继承
function Parent(age) {
this.age = age
this.name = 'tom'
}
Parent.prototype.sayName = function () {
console.log(this.name)
}
function Child(name, age) {
Parent.call(this, name, age)
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
function deepClone(source) {
let tar = source.constructor == Array ? [] : {}
for (let key in source) {
if (source[key] && source.hasOwnProperty(key)) {
if (typeof source == 'object') {
tar[key] = source[key].constructor == Array ? [] : {}
tar[key] = deepClone(source[key])
} else {
tar[key] = source[key]
}
}
}
return tar
}
curry
function curry(fn) {
if (fn.length < 1) return fn
const generate = (...args) => {
if (fn.length == args.length) {
return fn(...args)
} else {
return (...arg) => {
return generate(...args, ...arg)
}
}
}
return generate
}
EventBus
class EventBus {
constructor() {
this.catch = {}
}
on(name, fun) {
let tasks = this.catch[name]
if (tasks) {
this.catch[name].push(fun)
} else {
this.catch[name] = [fun]
}
}
off(name, fun) {
let tasks = this.catch[name]
if (tasks) {
let index = tasks.findIndex(item => item.fun == fun)
this.catch[name].splice(index, 1)
}
}
emit(name, once = false, ...args) {
if (this.catch[name]) {
let tasks = this.catch[name].slice()
for (let fn of tasks) {
fn(...args)
}
}
if (once) {
delete this.catch[name]
}
}
}
promise.all 和 promise.race
const myPromiseAll = function (promiseList) {
return new Promise((resolve, reject) => {
let count = 0
let ans = []
for (let i = 0; i < promiseList.length; ++i) {
promiseList[i]
.then(res => {
ans[i] = res
count++
if (count == promiseList.length) {
resolve(ans)
}
})
.catch(err => {
reject(err)
})
}
})
}
const myPromiseRace = function (promiseList) {
return new Promise((resolve, reject) => {
promiseList.forEach(item => {
item.then(
val => resolve(val),
err => reject(err)
)
})
})
}
Promise.prototype.all = function (promises) {
//promises为 Array
let result = []
let promiseCount = 0
let promiseLength = promises.length
function isPromise(obj) {
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
}
return new Promise(function (resolve, reject) {
for (let i = 0; i < promiseLength; ++i) {
let cur = promises[i]
if (isPromise(cur)) {
// cur.then((res)=>{
Promise.resolve(cur).then(
res => {
promiseCount++
result[i] = res
if ((promiseCount = promiseLength)) {
resolve(result)
}
},
err => {
reject(err)
}
)
} else {
result[i] = promises[i]
resolve(result)
}
s
}
})
}
jsonp
const myJsonp = function (url, params, callback) {
let generate = () => {
let str = ''
for (let key in params) {
if (Object.prototype.hasOwnProperty.call(params, key)) {
str += `${key}=${params[key]}&`
}
}
str += `callback=${callback}`
return `${url}?${str}`
}
return new Promise((resolve, reject) => {
let script = document.createElement('script')
script.src = generate()
document.body.appendChild(script)
window[callback] = data => {
resolve(data)
document.removeChild(script)
}
})
}
ajax
const myAjax = function (url) {
return new Promise((resolve, reject) => {
let xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('MscroSoft.XMLHttp')
xhr.open('GET', url, false)
xhr.setRequestHeader('Accept', 'application/json')
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return
if (xhr.status == 200 || xhr.status == 304) {
resolve(xhr.responseText)
} else {
reject(new Error(xhr.responseText))
}
}
xhr.send()
})
}
lazyload
const lazyload = function () {
const imgs = document.getElementsByTagName('img')
const len = imgs.length
// 视口的高度
const viewHeight = document.documentElement.clientHeight
// 滚动条高度
const scrollHeight = document.documentElement.scrollTop || document.body.scrollTop
for (let i = 0; i < len; i++) {
const offsetHeight = imgs[i].offsetTop
if (offsetHeight < viewHeight + scrollHeight) {
const src = imgs[i].dataset.src
imgs[i].src = src
}
}
}
滚动加载
window.addEventListener(
'scroll',
function () {
const clientHeight = document.documentElement.clientHeight
const scrollTop = document.documentElement.scrollTop
const scrollHeight = document.documentElement.scrollHeight
if (clientHeight + scrollTop >= scrollHeight) {
// 检测到滚动至页面底部,进行后续操作
// ...
}
},
false
)
深拷贝
function deepClone(tar, map = new Map()) {
if (typeof tar == 'object') {
let target = Array.isArray(tar) ? [] : {}
if (map.get(tar)) {
return map.get(tar)
}
map.set(tar, target)
for (let key in tar) {
target[key] = clone(tar[key], map)
}
return target
} else {
return tar
}
}
防抖 节流
function debounce(event, time, flag) {
let time = null
return function (...args) {
clearTimeout(time)
if (flag && !time) {
event.apply(this, args)
}
time = setTimeout(() => {
event.apply(this, args)
}, time)
}
}
function throttle(event, time) {
let timer = null
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
timer = null
event.apply(this, args)
}, time)
}
}
}
localStorage 设置过期时间
export function setLocalStorageWithExpire(key, value, expire) {
// expire单位为天
if (isNaN(expire) || expire < 1) {
throw new Error('有效期应为一个有效数值')
}
let time = expire * 86400000
let obj = {
data: value, //存储值
time: Date.now(), //存值时间戳
expire: time, //过期时间
}
localStorage.setItem(key, JSON.stringify(obj))
}
export function getLocalStorageWithExpire(key) {
let val = localStorage.getItem(key)
if (!val) return val
val = JSON.parse(val)
if (Date.now() > val.time + val.expire) {
localStorage.removeItem(key)
return
}
return val.data
}
// enum.ts
//字典 Dictionaries expire过期时间key permanent永久不过期
export enum Dictionaries {
expire = '__expire__',
permanent = 'permanent'
}
// type.ts
import { Dictionaries } from "../enum"
export type Key = string //key类型
export type expire = Dictionaries.permanent | number //有效期类型
export interface Data<T> { //格式化data类型
value: T
[Dictionaries.expire]: Dictionaries.expire | number
}
export interface Result<T> { //返回值类型
message: string,
value: T | null
}
export interface StorageCls { //class方法约束
set: <T>(key: Key, value: T, expire: expire) => void
get: <T>(key: Key) => Result<T | null>
remove: (key: Key) => void
clear: () => void
}
// index.ts
import { StorageCls, Key, expire, Data,Result } from "./type";
import { Dictionaries } from "./enum";
export class Storage implements StorageCls {
//存储接受 key value 和过期时间 默认永久
public set<T = any>(key: Key, value: T, expire: expire = Dictionaries.permanent) {
//格式化数据
const data = {
value,
[Dictionaries.expire]: expire
}
//存进去
localStorage.setItem(key, JSON.stringify(data))
}
public get<T = any>(key: Key):Result<T | null> {
const value = localStorage.getItem(key)
//读出来的数据是否有效
if (value) {
const obj: Data<T> = JSON.parse(value)
const now = new Date().getTime()
//有效并且是数字类型 并且过期了 进行删除和提示
if (typeof obj[Dictionaries.expire] == 'number' && obj[Dictionaries.expire] < now) {
this.remove(key)
return {
message:`您的${key}已过期`,
value:null
}
}else{
//否则成功返回
return {
message:"成功读取",
value:obj.value
}
}
} else {
//否则key值无效
console.warn('key值无效')
return {
message:`key值无效`,
value:null
}
}
}
//删除某一项
public remove(key:Key) {
localStorage.removeItem(key)
}
//清空所有值
public clear() {
localStorage.clear()
}
}
取对象深度嵌套的属性
/**
* 安全读取对象深度嵌套的属性,遇到不存在的属性会返回 undefined,避免报错
*
* @param {object} target 目标对象
* @param {string} path 属性路径,为点语法组成的字符串,支持字面量,可以使用模板字符串支持变量
* @return {any} 返回对象的属性值
* @用例 getProp(obj, 'a.b.c') => obj.a.b.c
* @用例 getProp(obj, `a.${this.b}.c`) => obj.a[this.b].c
*/
export function getProp(target, path) {
return path.split('.').reduce((obj, key) => {
return obj && obj[key]
}, target)
}