深拷贝
// 深拷贝
function deepClone(ori) {let tar;if (typeof ori === 'object' && ori !== null) {tar = Array.isArray(ori) ? [] : {}for (let k in ori) {if (ori.hasOwnProperty(k)) {tar[k] = deepClone(ori[k])}}} else {tar = ori}return tar}
继承
// 圣杯模式实现继承
function Parent() { }
function Child() { }
function Buffer() { }
Buffer.prototype = Parent.prototype
Child.prototype = new Buffer()
Child.prototype.constructor = Child
Child.prototype.super_class = Parent
// ES6 类的继承
class Parent { }
class Child extends Parent {constructor() {super()}
}
// 组合继承
function Child() {Parent.call(this)
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
Promise
// Promise
const pending = Symbol('pending')
const fulfilled = Symbol('fulfilled')
const rejected = Symbol('rejected')class Promise {constructor(executor) {this.status = 'pending'this.value = undefinedthis.reason = undefinedthis.onFulfilledCbs = []this.onRejectedCbs = []function resolve(value) {if (this.status === 'pending') {this.status = 'fulfilled'this.value = valuethis.onFulfilledCbs.forEach(fn => fn())}}function reject(reason) {if (this.status === 'pending') {this.status = 'rejected'this.reason = reasonthis.onRejectedCbs.forEach(fn => fn())}}try {executor(resolve, reject)} catch (err) {reject(err)}}then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => valueonRejected = typeof onRejected === 'function' ? onRejected : reason => reason// 异步返回promiselet promise = new Promise((resolve, reject) => {if (this.status === 'fulfilled') {setTimeout(() => {try {let x = onFulfilled(this.value)resolvePromise(promise, x, resolve, reject)} catch (e) {reject(e)}});}if (this.status === 'rejected') {setTimeout(() => {try {let x = onRejected(this.reason)resolvePromise(promise, x, resolve, reject)} catch (e) {reject(e)}});}if (this.status === 'pending') {this.onFulfilledCbs.push(() => {setTimeout(() => {try {let x = onFulfilled(this.value)resolvePromise(promise, x, resolve, reject)} catch (e) {reject(e)}});})this.onRejectedCbs.push(() => {setTimeout(() => {try {let x = onRejected(this.reason)resolvePromise(promise, x, resolve, reject)} catch (e) {reject(e)}});})}})return promise}// Promise构造器上方法static resolve(result) {return new Promise((resolve) => {resolve(result)})}static resolve(reason) {return new Promise((resolve, reject) => {reject(reason)})}static all(iterator) {return new Promise((resolve, reject) => {const final = []for (let item of iterator) {Promise.resolve(item).then(result => {final.push(result)if (final.length === iterator.length) {resolve(final)}}, reason => {reject(reason)})}})}static race(iterator) {return new Promise((resolve, reject) => {for (let item of iterator) {Promise.resolve(item).then(resolve, reject)}})}
}
function resolvePromise(promise, x, resolve, reject) {if (x === promise) {return reject(new TypeError('chaining cycle'))}let called;if (x !== null && (typeof x === 'function' || typeof x === 'object')) {try {let then = x.thenif (typeof then === 'function') {then.call(x, y => {if (called) returncalled = trueresolvePromise(promise, y, resolve, reject)}, err => {if (called) returncalled = truereject(err)})} else {if (called) returncalled = trueresolve(x)}} catch (err) {if (called) returncalled = truereject(err)}} else {resolve(x)}
}
防抖节流
// 防抖
function debounce(fn, delay, triggerNow) {let t = null;return function () {let _this = thisif (t) {clearTimeout(t)}if (triggerNow) {let exec = !tt = setTimeout(function () {t = null}, delay);if (exec) {fn.apply(_this, arguments)}} else {t = setTimeout(function () {fn.apply(_this, arguments)}, delay);}}
}
// 节流 不会立即执行
function throttle1(fn, delay) {let t = null, begin = Date.now();return function () {_this = thisclearTimeout(t)const cur = Date.now()if (cur - begin >= delay) {fn.apply(_this, arguments) // 就执行吧begin = cur} else {t = setTimeout(function () {fn.apply(_this, arguments)}, delay);}}
}
// 节流 且会立即执行
function throttle2(fn, delay) {let valid = true // 初始化开着return function () {if (!valid) returnvalid = false // 先关了t = setTimeout(function () {fn.apply(_this, arguments)value = true // 定时器里再开起来}, delay);}
}
call、bind、apply
// call、bind、apply
// fn.call(obj, ...args)
// 第一个参数是this指向
Function.prototype.call = function (context = window, ...args) {// this指向这个函数const fn = Symbol('fn')context[fn] = thiscontext[fn](...args) // 隐式绑定delete context[fn]
}
Function.prototype.apply = function (context = window, argsArr) {// this指向这个函数const fn = Symbol('fn')context[fn] = thiscontext[fn](...argsArr) // 隐式绑定delete context[fn]
}
Function.prototype.bind = function (context = window, ...args) {// this指向这个函数const fn = Symbol('fn')context[fn] = thisreturn function (..._args) {let arr = [...args, ..._args]context[fn](...arr)delete context[fn]}
}
排序算法
// 冒泡排序算法
function bubbleSort(arr) {let len = arr.lengthfor (let i = 0; i < len - 1; i++) {for (let j = 0; j < len - 1 - i; j++) {let a = arr[j],b = arr[j + 1]if (a > b) {[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]}}}return arr
}
console.log(bubbleSort([2, 1, 4, 0, 3]))
// 阮一峰分而治之 快排的思想 但在复杂度上没有真正的快排好 只能作为辅助理解
function quickSort(arr) {let len = arr.length// 非常重要 否则死循环if (len <= 1) {return arr}let pivotIndex = Math.floor(len / 2)let pivot = arr.splice(pivotIndex, 1)[0]let left = [], right = []for (let item of arr) {if (item < pivot) {left.push(item)} else {right.push(item)}}return [...quickSort(left), pivot, ...quickSort(right)]
}
console.log(quickSort([2, 1, 4, 0, 3]))function quickSort(arr, left, right) {var partitionIndex;if (left < right) {partitionIndex = partition(arr, left, right);quickSort(arr, left, partitionIndex - 1);quickSort(arr, partitionIndex + 1, right);}return arr;
}
// 找基准
function partition(arr, left, right) {var pivotIndex = left,index = pivotIndex + 1;for (var i = index; i <= right; i++) {if (arr[i] < arr[pivotIndex]) {swap(arr, i, index);index++; // index会变}}swap(arr, pivotIndex, index - 1);return index - 1;
}
function swap(arr, i, j) {[arr[i], arr[j]] = [arr[j], arr[i]]
}
console.log(quickSort(test, 0, test.length - 1))
// 斐波那契数列
function* test(n) {let [prev, cur] = [0, 1];for (let i = 0; i < n; i++) {yield prev;[prev, cur] = [cur, prev + cur];}
}
console.log(...test(15))
手写JSONP JSON with Padding
- 有src属性的标签如script img iframe能跨域
- 前端在得到了后端返回的内容jsonpCallback({“title”:“title1”}),发现里面是一段执行函数的语句
- 不能用Symbol,不能转为字符串
- 动态添加script,在定义在全局的callback中处理数据,并移除script
; (function (win) {function jsonp(url, params = {}, cb) {const src = Object.entries(params).map(([key, value]) => {return `${key}=${value}`}).join('&')const cbName = 'cb' + Date.now()const s = document.createElement('script')s.setAttribute('src', url + '?' + src + '&callback=' + cbName)document.body.appendChild(s)win[cbName] = function (res) {cb(res)document.body.removeChild(src)}}window.jsonp = jsonp
})(window);
三角形
setTimeout实现setInterval、clearInterval
- IIFE
- 全局的定时器id t
let t = null
function mysetInterval(cb, time) {;(function () {cb()t = setTimeout(arguments.callee, time)})();return t
}
t = mysetInterval(() => {console.log(1)
}, 500)
function myClearTnterVal(t) {clearTimeout(t)t = nullconsole.log(t)
}
setTimeout(() => {myClearTnterVal(t)
}, 1500)
lastPromise
编写一个高阶函数,这个高阶函数接受一个promise参数,然后返回一个函数。每次调用返回的函数的时候,只会输出最后一个promsie的结果。就像下面示例一样。
function lastPromise(promiseFunction) {// TODO
}// 示例
let count = 1;
// 这是一个函数,返回promise
let promiseFunction = () =>new Promise(rs =>setTimeout(() => {rs(count++);}));let lastFn = lastPromise(promiseFunction);lastFn().then(console.log); // 无输出
lastFn().then(console.log); // 无输出
lastFn().then(console.log); // 3
let count = 1;
// 这是一个函数,返回promise
let promiseFunction = () =>new Promise(rs =>setTimeout(() => {rs(count++);}));
function lastPromise(promiseFunction) {// 返回函数 函数有一个then方法let mC = 0return function () {mC++function then(cb) {promiseFunction().then(res => {if (mC == res) {cb(res)}})}return { then }}
}
let lastFn = lastPromise(promiseFunction)
lastFn().then(console.log)
lastFn().then(console.log)
lastFn().then(console.log)
animation动画 transition过渡 transform转换
画三角形
- 没宽高,看到的是边
- 边有left right top bottom 要分开写
- 左边是左上三角 右边是右上三角
- 下边是一个正三角
- 上边是一个倒三角
正方形
- vw
- 设置宽度,padding-top div里写字会撑高
单链表循环
快速排序
算24点
从左到右动画
- 不理解为何定位做不到抛物线效果,没有过渡
- 用transform就好,有移动
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<style>div {width: 50px;height: 50px;background: red;border-radius: 50%;position: absolute;animation: mymove 5s infinite;}@keyframes mymove {from {left: 0px;}to {left: 300px;}}
</style>
<body><div></div></div>
</body>
</html>
抛物线/贝塞尔曲线动画 没用到定位 用的是transform
- animation-timing-function控制直线/曲线轨迹
- linear:对角线运动
- 我的理解:ease-in缓慢开始 ease-out缓慢结束
- ease相关:抛物线运动ease-in ease-out (_
- ease-out ease-in:铅球 T)
- 需要2元素-2动画分别控制水平/竖直方向
- span和span:after
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>元素弧线运动</title><style>.box{width: 400px;height: 400px;border: 2px solid #ff8800;}span{display: block;width: 40px;height: 40px;border: 1px solid #222;animation: center1 2s linear forwards;}span:after{content: '';display: block;width: 40px;height: 40px;border-radius: 20px;background: greenyellow;animation: center2 2s linear forwards;}@keyframes center1 {to{transform: translateX(360px)}}@keyframes center2 {to{transform: translateY(360px)}}</style>
</head>
<body>
<div class="box"><span></span>
</div>
</body>
</html>
三角形翻转
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>三角形翻转</title><style>.box {width: 400px;height: 400px;border: 2px solid #ff8800;}span {display: block;width: 40px;height: 40px;/* border: 1px solid #222; *//* 隐藏了 */animation: center1 2s ease-out forwards;}span:after {content: '';display: block;width: 0;height: 0;border-top: 40px solid transparent;border-right: 40px solid greenyellow;animation: center2 2s ease-in forwards;}@keyframes center1 {to {transform: translateX(360px)}}@keyframes center2 {to {transform: translateY(360px) rotate(360deg)}}</style>
</head><body><div class="box"><span></span></div>
</body></html>
翻牌
- js实现,因为是点击事件触发的
- 正反面的rotateY都是减小的 正面0 → -180 反面180 → 0
- 正面一开始层级高 backface-visibility:hidden
- perspective: 看起来更有动效 2000px离远一点,太近长度变化太夸张
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>翻牌</title><style>div {position: absolute;width: 200px;height: 350px;line-height: 350px;text-align: center;transition: all 3s;perspective: 3000px;}.front {background: gainsboro;transform: rotateY(0);z-index: 1;backface-visibility: hidden;}.back {background: goldenrod;transform: rotateY(180deg);}</style>
</head><body><div class="box"><div class="front">正面</div><div class="back">反面</div></div><script>const oBox = document.getElementsByClassName('box')[0]console.log('oBox', oBox)oBox.onclick = function(){const oFront = document.getElementsByClassName('front')[0]const oBack = document.getElementsByClassName('back')[0]oFront.style = 'transform:rotateY(-180deg)'oBack.style = 'transform:rotateY(0)'}</script>
</body></html>
用reduce实现map
- reduce做累加可不能初始传[]进去,[]的toString为’’,最后reduce的结果会变成字符串join
const arr = [1, 2, 3, 4]
// arr.map(callback) 遍历每个元素 返回[] cb:item index arr
Array.prototype.myMap = function (cb) {const list = []this.reduce((prev, cur, index) => {const r2 = cb(cur, index, this)list.push(r2)}, [])// reduce初始从[]开始,保证index从0开始return list}
const res = arr.myMap((item, index, list) => {return item * 2
})
console.log(res)