1, this指向篇
call实现
es3:
Function.prototype.call2 = function(context) {
var context = context || window;
context.fn = this;
var args = [];
for (var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args + ')');
delete result.fn;
return result;
}
es5:
Function.prototype.call2 = function(context) {
const fn = Symbol('fn');
const args = [...arguments].slice(1);
var context = context || window;
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
}
apply实现
es3:
Function.prototype.apply = function (context, arr) {
context = context ? Object(context) : window;
context.fn = this;
var result;
// 判断是否存在第二个参数
if (!arr) {
result = context.fn();
} else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')');
}
delete context.fn
return result;
}
es5:
Function.prototype.apply = function (context, arr) {
context = context ? Object(context) : window;
context.fn = this;
let result;
if (!arr) {
result = context.fn();
} else {
result = context.fn(...arr);
}
delete context.fn
return result;
}
bind实现
Function.prototype.bind2 = function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {};
var fBound = function () {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
}
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}
2, 构造函数原型
new的实现
//创建一个新对象;
//将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
//执行构造函数中的代码(为这个新对象添加属性);
// 返回新对象.
function myNew() {
var obj = new Object();
var Constructor = Array.prototype.shift.call(arguments);
obj.__proto__ = Constructor.prototype;
var ret = Constructor.apply(obj, arguments);
return typeof ret === 'object' && ret !== null ? ret : obj;
}
instanceof的实现
function instance_of(L, R) {
var O = R.prototype;
L = L.__proto__;
while(true) {
if(L === null) return false;
if(O === L) return true;
L = L.__proto__;
}
}
Object.create的实现
Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
Object.create() = function create(prototype) {
// 排除传入的对象是 null 和 非object的情况
if (prototype === null || typeof prototype !== 'object') {
throw new TypeError(`Object prototype may only be an Object: ${prototype}`);
}
// 让空对象的 __proto__指向 传进来的 对象(prototype)
// 目标 {}.__proto__ = prototype
function Temp() {};
Temp.prototype = prototype;
return new Temp;
}
Object.assign
Object.assign(target, source1, ..., sourceN), 用于将源对象的所有可枚举属性复制到目标对象(target),其实就是浅拷贝的过程。
if(typeof Object.assign2 != 'function') {
Object.defineProperty(Object, 'assign2', {
value: function(target) {
'use strict';
if(target == null) {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if(nextSource != null) {
for(var nextKey in nextSource) {
if(Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writeable: true,
configuration: true
});
}
原生数据类型检测简易封装
Object.prototype.isType = function (type) {
return function (params) {
return Object.prototype.toString.call(params) === `[object ${type}]`
}
}
let isString = Object.isType('String')
let isArray = Object.isType('Array')
console.log(isString(1)) // false
console.log(isString('hello')) // true
console.log(isArray(2)) // false
console.log(isArray(['hello'])) // true
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
3, 克隆拷贝
浅拷贝
浅拷贝:只拷贝对象或数组的第一层内容
const shallClone = (target) => {
if (typeof target === 'object' && target !== null) {
const cloneTarget = Array.isArray(target) ? [] : {};
for (let prop in target) {
if (target.hasOwnProperty(prop)) { // 遍历对象自身可枚举属性(不考虑继承属性和原型对象)
cloneTarget[prop] = target[prop];
}
return cloneTarget;
} else {
return target;
}
}
深拷贝
深拷贝:深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。
简单版
JSON.parse(JSON.stringify(source));
深度版
function deepCopy(obj, cache = new WeakMap()) {
if (!obj instanceof Object) return obj
// 防止循环引用
if (cache.get(obj)) return cache.get(obj)
// 支持函数
if (obj instanceof Function) {
return function () {
return obj.apply(this, arguments)
}
}
// 支持日期
if (obj instanceof Date) return new Date(obj)
// 支持正则对象
if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags)
// 还可以增加其他对象,比如:Map, Set等,根据情况判断增加即可,面试点到为止就可以了
// 数组是 key 为数字素银的特殊对象
const res = Array.isArray(obj) ? [] : {}
// 缓存 copy 的对象,用于处理循环引用的情况
cache.set(obj, res)
Object.keys(obj).forEach((key) => {
if (obj[key] instanceof Object) {
res[key] = deepCopy(obj[key], cache)
} else {
res[key] = obj[key]
}
});
return res
}
// 测试
const source = {
name: 'Jack',
meta: {
age: 12,
birth: new Date('1997-10-10'),
ary: [1, 2, { a: 1 }],
say() {
console.log('Hello');
}
}
}
source.source = source
const newObj = deepCopy(source)
console.log(newObj.meta.ary[2] === source.meta.ary[2]); // false
console.log(newObj.meta.birth === source.meta.birth); // false
4, 防抖截流
防抖
防抖:指触发事件后在规定时间内回调函数只能执行一次,如果在规定时间内又触发了该事件,则会重新开始算规定时间。总结即延迟执行;
function debounce(fn, wait, immediate) {
let timer = null;
return function(...args) {
// 立即执行的功能(timer为空表示首次触发)
if (immediate && !timer) {
fn.apply(this, args);
}
// 有新的触发,则把定时器清空
timer && clearTimeout(timer);
// 重新计时
timer = setTimeout(() => {
fn.apply(this, args);
}, wait)
}
}
截流
截流:当持续触发事件时,在规定时间段内只能调用一次回调函数。如果在规定时间内又触发了该事件,则什么也不做,也不会重置定时器. 实现类型有时间戳版本和定时器版本;
定时器:
特点:n秒后开始执行第一次,停止触发后还会再执行一次;
function throttle(fn, wait) {
let timer = null;
return function(...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, wait)
}
}
}
时间戳:
特点:开始触发会立即执行,停止触发后不再执行;
function throttle(fn, wait) {
let previous = 0;
return function(...args) {
let now = +new Date();
if (now - previous > wait) {
previous = now;
fn.apply(this, args);
}
}
}
6, 数组对象
数组扁平化
// 使用flat
const res1 = arr.flat(Infinity);
// 使用reduce
const flatten = arr => {
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
}, [])
}
const res4 = flatten(arr);
//使用递归
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
var result = [];
for (var i = 0, len = arr.length; i < len; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]))
}
else {
result.push(arr[i])
}
}
return result;
}
console.log(flatten(arr))
对象扁平化
function objectFlat(obj = {}) {
const res = {}
function flat(item, preKey = '') {
Object.entries(item).forEach(([key, val]) => {
const newKey = preKey ? `${preKey}.${key}` : key
if (val && typeof val === 'object') {
flat(val, newKey)
} else {
res[newKey] = val
}
})
}
flat(obj)
return res
}
// 测试
const source = { a: { b: { c: 1, d: 2 }, e: 3 }, f: { g: 2 } }
console.log(objectFlat(source));
数组去重
const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}];
// => [1, '1', 17, true, false, 'true', 'a', {}, {}]
利用set:
const res1 = Array.from(new Set(arr));
两层循环:
const unique1 = arr => {
let len = arr.length;
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
// 每删除一个树,j--保证j的值经过自加后不变。同时,len--,减少循环次数提升性能
len--;
j--;
}
}
}
return arr;
}
indexOf:
const unique2 = arr => {
const res = [];
for (let i = 0; i < arr.length; i++) {
if (res.indexOf(arr[i]) === -1) res.push(arr[i]);
}
return res;
}
include:
const unique3 = arr => {
const res = [];
for (let i = 0; i < arr.length; i++) {
if (!res.includes(arr[i])) res.push(arr[i]);
}
return res;
}
filter:
const unique4 = arr => {
return arr.filter((item, index) => {
return arr.indexOf(item) === index;
});
}
Map:
const unique5 = arr => {
const map = new Map();
const res = [];
for (let i = 0; i < arr.length; i++) {
if (!map.has(arr[i])) {
map.set(arr[i], true)
res.push(arr[i]);
}
}
return res;
}
reduce实现
Array.prototype._reduce = function (callback, initVal) {
let i = 0
let result = initVal
if (typeof initVal === 'undefined') {
result = this[0]
i++
}
for (i; i < this.length; i++) {
result = callback(result, this[i])
}
return result
}
const arr = [1, 2, 3]
let result = arr._reduce((a, b) => {
return a + b
}, 0)
console.log(result) // 6
push和pop实现
//Array的push底层实现是依赖于 数组的length属性的
Array.prototype.push2 = function(...rest){
this.splice(this.length, 0, ...rest)
return this.length;
}
Array.prototype.pop2 = function(){
return this.splice(this.length - 1, 1)[0];
}
6, Promise
完整版
function Promise(executor) {
let _this = this;
this.state = "pending";
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
// 讓其處理器函數立即執行
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
function resolve(value) {
if (_this.state === "pending") {
_this.state = "resolved";
_this.value = value;
_this.onResolvedCallbacks.forEach(fn => fn(value))
}
}
function reject(reason) {
if (_this.state === "pending") {
_this.state = "rejected";
_this.reason = reason;
_this.onRejectedCallbacks.forEach(fn => fn(reason))
}
}
}
Promise.prototype.then = function(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
onRejected = typeof onRejected === "function" ? onRejected : err => { throw err }
let promise2 = new Promise((resolve, reject) => {
if (this.state === "pending") {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject (e)
}
}, 0)
})
}
if (this.state === "resolved") {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}
if (this.state === "rejected") {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}
})
return promise2;
}
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected)
}
Promise.resolve = function(val) {
// 直接抛出一个成功状态的Promise
return new Promise((resolve, reject) => {
resolve(val)
})
}
Promise.reject = function(val) {
// 直接抛出一个拒绝状态的Promise
return new Promise((resolve, reject) => {
reject(val)
})
}
// race方法
Promise.race = function(promises) {
// return一个Promise
return new Promise((resolve, reject) => {
// 遍历执行promises
for (let i = 0; i < promises.length; i++) {
// then只要接收到状态改变,直接抛出
promises[i].then(resolve, reject)
}
})
}
// all方法
Promise.all = function(arr) {
// 只有一个目的 获取到所有的promise,都执行then,把结果放到数组,一起返回
// 递归实现和遍历实现都可以
// 用于存放每次执行后返回结果
let aResult = []
return new Promise(function(resolve, reject) {
let i = 0
// 开始逐次执行数组中的函数(重要)
next()
function next() {
arr[i].then(function(res) {
// 存储每次得到的结果
aResult.push(res)
i++
if (i >= arr.length) {
// 如果函数数组中的函数都执行完,便resolve
resolve(aResult)
} else {
next()
}
})
}
})
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject( new TypeError('請避免Promise循環引用'))
}
let called;
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === "function") {
then.call(x, (y) => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject)
}, (r) => {
if (called) return;
called = true;
reject(r)
})
} else {
resolve(x)
}
} catch (e) {
if (called) return;
called = true;
reject(e)
}
} else {
resolve(x)
}
}
// promises-aplus-tests测试
Promise.defer = Promise.deferred = function() {
let defer = {}
defer.promise = new Promise((resolve, reject) => {
defer.resolve = resolve
defer.reject = reject
})
return defer
}
try {
module.exports = Promise
} catch (e) {}
面试版
function myPromise(constructor){
let self=this;
self.status="pending" //定义状态改变前的初始状态
self.value=undefined;//定义状态为resolved的时候的状态
self.reason=undefined;//定义状态为rejected的时候的状态
function resolve(value){
//两个==="pending",保证了状态的改变是不可逆的
if(self.status==="pending"){
self.value=value;
self.status="resolved";
}
}
function reject(reason){
//两个==="pending",保证了状态的改变是不可逆的
if(self.status==="pending"){
self.reason=reason;
self.status="rejected";
}
}
//捕获构造异常
try{
constructor(resolve,reject);
}catch(e){
reject(e);
}
}
myPromise.prototype.then=function(onFullfilled,onRejected){
let self=this;
switch(self.status){
case"resolved":
onFullfilled(self.value);
break;
case"rejected":
onRejected(self.reason);
break;
default:
}
}
Promise.all的實現
function promiseAll(promises) {
return new Promise(function(resolve, reject) {
let resolvedCounter = 0;
let resolveNum = promises.length;
var resolvedValues = new Array(resolveNum);
for (let i = 0; i < resolveNum; i++) {
Promise.resolve(promises[i]).then(function(value) {
resolvedCounter++;
resolvedValues[i] = value;
if(resolvedCounter === resolveNum) {
return resolve(resolvedValues)
}
}, function(reason) {
return reject(reason);
})
}
})
}
var p1 = Promise.resolve(1),
p2 = Promise.resolve(2),
p3 = Promise.resolve(3);
promiseAll([p1, p2, p3]).then(function (results) {
console.log(results); // [1, 2, 3]
});
7, Async/await
function _asyncToGenerator(fn) {
return function() {
var self = this,
args = arguments;
// 将返回值promise化
return new Promise(function(resolve, reject) {
// 获取迭代器实例
var gen = fn.apply(self, args);
// 执行下一步
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
}
// 抛出异常
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
}
// 第一次触发
_next(undefined);
});
};
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
// 迭代器完成
resolve(value);
} else {
// -- 这行代码就是精髓 --
// 将所有值promise化
// 比如 yield 1
// const a = Promise.resolve(1) a 是一个 promise
// const b = Promise.resolve(a) b 是一个 promise
// 可以做到统一 promise 输出
// 当 promise 执行完之后再执行下一步
// 递归调用 next 函数,直到 done == true
Promise.resolve(value).then(_next, _throw);
}
}
const asyncFunc = _asyncToGenerator(function*() {
const e = yield new Promise(resolve => {
setTimeout(() => {
resolve('e');
}, 1000);
});
const a = yield Promise.resolve('a');
const d = yield 'd';
const b = yield Promise.resolve('b');
const c = yield Promise.resolve('c');
return [a, b, c, d, e];
});
asyncFunc().then(res => {
console.log(res);
});
8, 设计模式
实现双向绑定
defineProperty版本
// 数据
const data = {
text: 'default'
};
const input = document.getElementById('input');
const span = document.getElementById('span');
// 数据劫持
Object.defineProperty(data, 'text', {
// 数据变化 --> 修改视图
set(newVal) {
input.value = newVal;
span.innerHTML = newVal;
}
});
// 视图更改 --> 数据变化
input.addEventListener('keyup', function(e) {
data.text = e.target.value;
});
proxy版本
// 数据
const data = {
text: 'default'
};
const input = document.getElementById('input');
const span = document.getElementById('span');
// 数据劫持
const handler = {
set(target, key, value) {
target[key] = value;
// 数据变化 --> 修改视图
input.value = value;
span.innerHTML = value;
return value;
}
};
const proxy = new Proxy(data, handler);
// 视图更改 --> 数据变化
input.addEventListener('keyup', function(e) {
proxy.text = e.target.value;
});
实现基本的Event Bus
class EventEmeitter {
constructor() {
this._events = this._events || new Map();
this._maxListeners = this._maxListeners || 10;
}
}
EventEmeitter.prototype.emit = function(type, ...args) {
let handler;
handler = this._events.get(type);
if (Array.isArray(handler)) {
for (let i = 0; i < handler.length; i++) {
if (args.length > 0) {
handler[i].apply(this, args);
} else {
handler[i].call(this);
}
}
} else {
if (args.length > 0) {
handler.apply(this, args);
} else {
handler.call(this);
}
}
return true;
};
EventEmeitter.prototype.addListener = function(type, fn) {
const handler = this._events.get(type);
if (!handler) {
this._events.set(type, fn);
} else if (handler && typeof handler === "function") {
this._events.set(type, [handler, fn]);
} else {
handler.push(fn);
}
};
EventEmeitter.prototype.removeListener = function(type, fn) {
const handler = this._events.get(type);
if (handler && typeof handler === "function") {
this._events.delete(type, fn);
} else {
let postion;
for (let i = 0; i < handler.length; i++) {
if (handler[i] === fn) {
postion = i;
} else {
postion = -1;
}
}
if (postion !== -1) {
handler.splice(postion, 1);
if (handler.length === 1) {
this._events.set(type, handler[0]);
}
} else {
return this;
}
}
};
let emitter = new EventEmeitter()
emitter.addListener('ages', age => {
console.log(age)
})
emitter.emit('ages', 18)
实现观察者模式
观察者模式(基于发布订阅模式) 有观察者,也有被观察者
class Subject { // 被观察者 学生
constructor(name) {
this.state = '开心的'
this.observers = []; // 存储所有的观察者
}
// 收集所有的观察者
attach(o){ // Subject. prototype. attch
this.observers.push(o)
}
// 更新被观察者 状态的方法
setState(newState) {
this.state = newState; // 更新状态
// this 指被观察者 学生
this.observers.forEach(o => o.update(this)) // 通知观察者 更新它们的状态
}
}
class Observer{ // 观察者 父母和老师
constructor(name) {
this.name = name
}
update(student) {
console.log('当前' + this.name + '被通知了', '当前学生的状态是' + student.state)
}
}
let student = new Subject('学生');
let parent = new Observer('父母');
let teacher = new Observer('老师');
// 被观察者存储观察者的前提,需要先接纳观察者
student. attach(parent);
student. attach(teacher);
student. setState('被欺负了');
9, 高阶函数
函数柯里化
**含义:**是给函数分步传递参数,每次传递部分参数,并返回一个更具体的函数接收剩下的参数,这中间可嵌套多层这样的接收部分参数的函数,直至返回最后结果。
// add的参数不固定,看有几个数字累计相加
function add (a,b,c,d) {
return a+b+c+d
}
function currying (fn, ...args) {
// fn.length 回调函数的参数的总和
// args.length currying函数 后面的参数总和
// 如:add (a,b,c,d) currying(add,1,2,3,4)
if (fn.length === args.length) {
return fn(...args)
} else {
// 继续分步传递参数 newArgs 新一次传递的参数
return function(...newArgs) {
// 将先传递的参数和后传递的参数 结合在一起
let allArgs = [...args, ...newArgs]
return currying(fn, ...allArgs)
}
}
}
let fn1 = currying(add, 1, 2) // 3
let fn2 = fn1(3) // 6
let fn3 = fn2(4) // 10
偏函数
function partial(fn) {
var args = [].slice.call(arguments, 1);
return function() {
var newArgs = args.concat([].slice.call(arguments));
return fn.apply(this, newArgs);
};
};
10, 其他
图片懒加载
var viewHeight = document.documentElement.clientHeight;
function lazyload() {
var imgs = document.querySelectorAll('img[data-original][lazyload]');
imgs.forEach(item => {
if (item.dataset.original == '') {
return;
}
var rect = item.getBoundingClientRect();
if (rect.bottom >= 0 && rect.top < viewHeight) {
var img = new Image();
img.src = item.dataset.original;
img.onload = function() {
item.src = img.src;
}
item.removeAttribute('data-original');
item.removeAttribute('lazyload')
}
})
}
lazyload();
document.addEventListener('scroll', lazyload)
解析URL为对象
function parseParam(url) {
const paramsStr = /.+\?(.+)$/.exec(url)[1];
const paramsArr = paramsStr.split('&');
let paramsObj = {};
paramsArr.forEach(param => {
if (/=/.test(param)) { // 处理有 value 的参数
let [key, val] = param.split('='); // 分割 key 和 value
val = decodeURIComponent(val); // 解码
val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字
if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则添加一个值
paramsObj[key] = [].concat(paramsObj[key], val);
} else { // 如果对象没有这个 key,创建 key 并设置值
paramsObj[key] = val;
}
} else { // 处理没有 value 的参数
paramsObj[param] = true;
}
})
return paramsObj;
}
let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';
parseParam(url)
/* 结果
{ user: 'anonymous',
id: [ 123, 456 ], // 重复出现的 key 要组装成数组,能被转成数字的就转成数字类型
city: '北京', // 中文需解码
enabled: true, // 未指定值得 key 约定为 true
}
*/
封装异步加载图片方法
function loadImg(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = function() {
console.log('一张图片加载完成');
resolve(img);
};
img.onerror = function() {
rejecct(new Error('ccould not load image ad' + url));
}
img.src = url;
})
}
红绿灯
红灯3秒亮一次,黄灯2秒亮一次,绿灯1秒亮一次,交替进行
function red() {
console.log('red');
}
function green() {
console.log('green');
}
function yellow() {
console.log('yellow');
}
const light = function(timer, cb) {
return new Promise(resolve => {
setTimeout(() => {
cb();
resolve()
}, timer)
})
}
const step = function() {
Promise.resolve().then(() => {
return light(3000, red)
}).then(() => {
return light(2000, green)
}).then(() => {
return light(1000, yellow)
}).then(() => {
return step()
})
}
step();
setTimeout实现setInterval
function mySetInterval(fn, millisec,count){
function interval(){
if(typeof count ==='undefined'||count-- > 0){
setTimeout(interval, millisec);
try{
fn()
}catch(e){
count = 0;
throw e.toString();
}
}
}
setTimeout(interval, millisec)
}
const fn = function() {
console.log(new Date());
}
mySetInterval(fn, 1000, 10);
使用promise+async await实现异步循环打印
let sleep = function(time, i) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(i);
}, time);
})
}
let start = async function() {
for (let i = 0; i < 6; i++) {
let result = await sleep(1000, i);
console.log(result);
}
}
start();
使用Promise实现每隔1秒输出1 2 3
const arr = [1, 2, 3];
arr.reduce((p, x) => {
return p.then(() => {
return new Promise(r => {
setTimeout(() => r(console.log(x)), 1000)
})
})
}, Promise.resolve());
下划线命名改为驼峰命名
function toCamelCase(str) {
if(typeof str !== 'string') {
return str;
}
return str.split('_')
.map(item => item.charAt(0).toUpperCase() + item.substr(1, item.length))
.join('');
}
toCamelCase('stoney_is_my_name');
js 实现sleep函数
利用一个伪死循环阻塞主线程
function sleep(delay) {
var start = (new Date()).getTime();
while ((new Date()).getTime() - start < delay) {
continue;
}
}
function test() {
console.log('111');
sleep(2000);
console.log('222');
}
定时器
function sleep1(ms, callback) {
setTimeout(callback, ms)
}
//sleep 1s
sleep1(1000, () => {
console.log(1000)
})
es6异步处理
const sleep = time => {
return new Promise(resolve => setTimeout(resolve,time)
) }
sleep(1000).then(()=>{ console.log(1) })
es7---- async/await是基于Promise的,是进一步的一种优化
function sleep(time) {
return new Promise(resolve =>
setTimeout(resolve,time)
) }
async function output() {
let out = await sleep(1000);
console.log(1);
return out;
}
output();
解构
// 将 destructuringArray([1, [2, 3], 4], "[a, [b], c]") => {a: 1, b: 2, c: 4}
const targetArray = [1, [2, 3], 4];
const formater = "[a, [b], c]";
const destructuringArray = (values, keys) => {
try {
const obj = {};
if (typeof keys === 'string') {
keys = JSON.parse(keys.replace(/\w+/g, '"$&"'));
}
const iterate = (values, keys) =>
keys.forEach((key, i) => {
if(Array.isArray(key)) iterate(values[i], key)
else obj[key] = values[i]
})
iterate(values, keys)
return obj;
} catch (e) {
console.error(e.message);
}
}
主动中止Promise调用链
const p1 = new Promise((resolve, reject) => {
setTimeout(() => { // 异步操作
resolve('start')
}, 1000);
});
p1.then((result) => {
console.log('a', result);
return Promise.reject('中断后续调用'); // 此时rejected的状态将直接跳到catch里,剩下的调用不会再继续
}).then(result => {
console.log('b', result);
}).then(result => {
console.log('c', result);
}).catch(err => {
console.log(err);
});
// a start
// 中断后续调用
每次加三的数组
const addThree = (start, target, arr = []) => {
if (start === target) {
arr.push(start)
return arr
}
if (start > target) {
return arr
}
arr.push(start)
return addThree(start += 3, target, arr)
}
console.log(addThree(3, 40))
字符串repeat实现
// 原生
'ni'.repeat(3); // 'ninini'
//一
String.prototype.repeatString1 = function (n) {
return Array(n + 1).join(this);
}
console.log('ni'.repeatString1(3));
//二
String.prototype.repeatString2 = function (n) {
return Array(n).fill(this).join('');
}
console.log('ni'.repeatString2(3));
渲染十万条数据
setTimeout(() => {
const total = 100000
const once = 20
const loopCount = total / once
let countOfRender = 0
let ul = document.querySelector("ul");
function add() {
const fragment = document.createDocumentFragment();
for (let i = 0; i < once; i++) {
const li = document.createElement("li");
li.innerText = Math.floor(Math.random() * total);
fragment.appendChild(li);
}
ul.appendChild(fragment);
countOfRender += 1;
loop();
}
function loop() {
if (countOfRender < loopCount) {
window.requestAnimationFrame(add);
}
}
loop();
}, 0);
es5实现继承
寄生组合式继承 核心实现是:用一个 F 空的构造函数去取代执行了 Parent 这个构造函数。
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log('parent name:', this.name);
}
function Child(name, parentName) {
Parent.call(this, parentName);
this.name = name;
}
function create(proto) {
function F(){};
F.prototype = proto;
return new F();
}
Child.prototype = create(Parent.prototype);
Child.prototype.sayName = function() {
console.log('child name:', this.name);
}
Child.prototype.constructor = Child;
var parent = new Parent('father');
parent.sayName();
var child = new Child('son', 'father');
child.sayName();
rem实现原理
// 原始配置
function setRem () {
let doc = document.documentElement
let width = doc.getBoundingClientRect().width
let rem = width / 75
doc.style.fontSize = rem + 'px'
}
addEventListener("resize", setRem)