# 代码实现
# LazyMan
设计 LazyMan 类,实现以下功能。
LazyMan('Tony');
// Hi I am Tony
LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch
LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food
实现思路就是将所有要执行的任务放一个队列中,然后再实现一个方法来有序得执行队列中任务
方法一:
function LazyManClass(name){
console.log(`Hi I am ${name}`)
this.stack = []
setTimeout(() => {
this.next()
})
return this
}
LazyManClass.prototype.next = async function(time){
let fn = this.stack.shift()
while(fn) {
await fn()
fn = this.stack.shift()
}
return this
}
LazyManClass.prototype.sleep = function(time){
this.stack.push(async function(){
await new Promise((resolve) => {
setTimeout(resolve, time*1000)
})
})
return this
}
LazyManClass.prototype.sleepFirst = function(time){
this.stack.unshift(async function(){
await new Promise((resolve) => {
setTimeout(() => {
resolve()
}, time*1000)
})
})
return this
}
LazyManClass.prototype.eat = function(foot){
this.stack.push(function(){
console.log(`I am eating ${foot}`)
})
return this
}
function LazyMan(name) {
return new LazyManClass(name)
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food')
注意上面 next
函数对 this.stack
遍历的时候,不能使用 forEacth
,因为这种特环方式不能正常执行异步函数
方式二:
class LazyManClass {
constructor(name) {
this.taskList = [];
this.name = name;
console.log(`Hi I am ${this.name}`);
setTimeout(() => {
this.next();
}, 0);
}
eat (name) {
var that = this;
var fn = (function (n) {
return function () {
console.log(`I am eating ${n}`)
that.next();
}
})(name);
this.taskList.push(fn);
return this;
}
sleepFirst (time) {
var that = this;
var fn = (function (t) {
return function () {
setTimeout(() => {
console.log(`等待了${t}秒...`)
that.next();
}, t * 1000);
}
})(time);
this.taskList.unshift(fn);
return this;
}
sleep (time) {
var that = this
var fn = (function (t) {
return function () {
setTimeout(() => {
console.log(`等待了${t}秒...`)
that.next();
}, t * 1000);
}
})(time);
this.taskList.push(fn);
return this;
}
next () {
var fn = this.taskList.shift();
fn && fn();
}
}
function LazyMan(name) {
return new LazyManClass(name);
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(4).eat('junk food');
# 实现 new
new
做了什么?
创建一个新对象
将
this
指向这个新对象将创建的对象的原型指向构造函数的原型
返回一个对象
- 新对象具有构造函数的所有属性和方法
function _New(fn, ...args){
const obj = Object.create(fn.prototype) // 完成了步骤1、2
const ret = fn.apply(obj, args)
return obj
}
Object.create()
Object.create()
方法创建一个新对象,使用现有的对象来提供新创建的对象的 __proto__
const person = {
isHuman: false,
printIntroduction: function () {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
}
};
const me = Object.create(person);
me.name = "Matthew"; // "name" is a property set on "me", but not on "person"
me.isHuman = true; // inherited properties can be overwritten
me.printIntroduction(); // My name is Matthew. Am I human? tru
# 网络请求失败自动重试功能函数封装
发起一个网络请求,遇到失败的情况,在规定时间(timeout)内,可以重复尝试(count)次.
- 当请求成功时返回正确信息
- 当超过规定时间时,返回超时
- 若重复尝试次数为0,且未超过超时时间时,返回错误信息。
- 可使用es7,8,9语法
function isTimeOut(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('超时')
}, time)
})
}
function repeatFetch(fn, count) {
return fn()
.catch(err => {
if(count === 0) {
return Promise.reject(err)
}
return repeatFetch(fn, --count)
})
}
/**
* @param { Function } fn : 请求方法
* @param { Number } count : 重复次数
* @param { Number } time : 过期时间
* */
function doFetch(fn, count, time) {
return Promise.race([isTimeOut(time), repeatFetch(fn, count)])
}
# 防抖
function de(fn, delay){
let timer = null
return function () {
clearTimeout(timer,)
timer = setTimeout(fn.bind(null, ...arguments), delay)
}
}
使用粟子:
// test
function testDebounce(e, content) {
console.log(e, content);
}
var testDebounceFn = debounce(testDebounce, 1000); // 防抖函数
document.onmousemove = function (e) {
testDebounceFn(e, 'debounce'); // 给防抖函数传参
}
# 劫流
function debounce(fn, delay) {
let running = false
return function () {
if(running) return
running = true
fn.apply(this, arguments); // 用apply指向调用debounce的对象,相当于_this.fn(args);
setTimeout(function () {
running = false
}, delay);
};
}
使用粟子:
// test
function testDebounce(e, content) {
console.log(e, content);
}
var testDebounceFn = debounce(testDebounce, 1000); // 防抖函数
document.onmousemove = function (e) {
testDebounceFn(e, 'debounce'); // 给防抖函数传参
}
# 实现instanceOf
instanceof
运算符用来检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上
// 定义构造函数
function C(){}
var o = new C();
o instanceof C; // true,
o instanceof Object; // true,
function isInstanceOf(obj, parent) {
while (obj.__proto__){
if(obj.__proto__ === parent.prototype){
return true
}
obj = obj.__proto__
}
return false
}
isInstanceOf([], Array) // true
isInstanceOf('abc', Array) // false
# 实现call、apply、bind
call
、 apply
、 bind
的作用就是改变的函数执行时的 this
指向
回顾一个函数的 this
是谁调用了函数,那么 this
就指向谁,所以可以根据这个特性来手机实现
call
// 方式一
function myCall(fn, obj, ...arg) {
obj.doFn = fn
return obj.doFn(...arg)
}
// 方式二
Function.prototype.myCall= function (ctx, ...arg) {
ctx.doFn = this
ctx.doFn(...arg)
delete ctx.doFn
}
apply
// 方式一
function myApply(fn, obj, arg) {
obj.doFn = fn
return obj.doFn(...arg)
}
// 方式二
Function.prototype.myApply= function (ctx, arg) {
ctx.doFn = this
ctx.doFn(...arg)
delete ctx.doFn
}
bind
// 方式二
function myBind(fn, obj, ...arg1) {
return (...arg2) => {
obj.doFn = fn
return obj.doFn(...arg1, ...arg2)
}
}
// 方式二
Function.prototype.myBind= function (ctx, arg1) {
return (...arg2) => {
ctx.doFn = this
let val = obj.doFn(...arg1, ...arg2)
delete ctx.doFn
return val
}
}
# 实现JSON.stringify()
JSON.stringify()
特性:
数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
undefined
、任意的函数以及symbol
值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)以
symbol
作为key
的属性也会被忽略对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
不可枚举的属性会被忽略
function myStringify(obj) {
let weak = new WeakSet()
let walk = (data) => {
if(typeof data !== 'object'){
return data
}
// 实现特性 5
if(weak.has(data)){
throw new Error('出现了循环了')
return
}
weak.add(data)
let type = Object.prototype.toString.call(data)
if(type !== '[object Array]' && type !== '[object Object]'){ // 简单实现特性 2
return data.toString()
}
let tem = []
// Object.keys 会自动过滤的 symbol 的key,实现特性5
Object.keys(data).forEach(item => {
let getTypeOf = typeof data[item]
if(getTypeOf === 'symbol' || getTypeOf === 'function'||getTypeOf===undefined) return // 实现特性 4
if(type === '[object Array]'){
tem.push(walk(data[item]))
} else if(type === '[object Object]'){
tem.push(`${item}:`+walk(data[item]))
}
})
if(type === '[object Array]'){
return `[${tem.join()}]`
} else if(type === '[object Object]'){
return `{${tem.join()}}`
}
}
return walk(obj)
}
let testMyStringify = {
a: new Number(1234),
b: 'ac',
arr: [1,2,3,4],
}
console.log('myStringify({})', myStringify(testMyStringify)) // {a:1234,b:ac,arr:[1,2,3,4]}
console.log('myStringify({})', JSON.stringify(testMyStringify)) //{"a":1234,"b":"ac","arr":[1,2,3,4]}
# 实现一个JSONparse
eval
方式
function strToJson(str) {
return eval('('+str+')')
}
new Functoin()
方式
function strToJson(str) {
return (new Function('return' + str))()
}
# 模拟Object.create
function create(proto) {
function F() {}
F.prototype = proto;
return new F();
}
# Promise
function _promise(fn) {
this.doResolve = null
this.doReject = null
this.sonResolve = null // then 返回的 promise
fn(this._resolve.bind(this), this._reject.bind(this))
}
_promise.prototype._resolve = function (data) {
if(!this.doResolve) return
queueMicrotask(() => {
let res = this.doResolve(data)
this.sonResolve(res)
})
}
_promise.prototype._reject = function (data) {
if(!this.doReject) return
queueMicrotask(() => {
let res = this.doReject(data)
this.sonResolve(res)
})
}
_promise.prototype.then = function (fn) {
this.doResolve = fn
return new _promise(resolve => {
this.sonResolve = resolve
})
}
_promise.prototype.catch = function (fn) {
this.doReject = fn
return new _promise(resolve => {
this.sonResolve = resolve
})
}
let pro = new _promise((resolve, reject) => {
setTimeout(() => {
resolve('哈哈')
}, 2000)
})
pro.then(res => {
console.log('第一个then', res)
return '自定义Promise', res
})
.then(res => {
console.log('第二个then',res)
})
# 手写-setTimeout 模拟实现 setInterval
function myInterval(fn, timer) {
let timeOut = null
let action = () =>{
timeOut = setTimeout(() => {
fn()
action()
}, timer)
}
action()
return function () {
clearTimeout(timeOut)
}
}
← 吱不吱二