/**
* 选择排序,时间复杂度为O(N^2)
*/
function selectSort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
let idxOfMinVal = i, curVal = arr[i];
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < curVal) {
curVal = arr[j];
idxOfMinVal = j;
}
}
if (idxOfMinVal != i) {
[arr[i], arr[idxOfMinVal]] = [arr[idxOfMinVal], arr[i]];
}
}
}
// test
const arr = new Array(10);
for (let i = 0; i < arr.length; i++) {
arr[i] = Math.round(Math.random() * 90 + 10)
}
console.log(arr);
selectSort(arr);
console.log(arr);
-
选择排序
-
冒泡排序
/** * 冒泡排序,时间复杂度为O(N^2) */ function bubbleSort(arr) { for (i = arr.length - 1; i > 0; i--) { for (j = 0; j < i; j++) { if (arr[j] > arr[j + 1]) { [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; } } } } // test const arr = new Array(10); for (let i = 0; i < arr.length; i++) { arr[i] = Math.round(Math.random() * 80 + 20) } console.log(arr); bubbleSort(arr); console.log(arr);
-
计算斐波拉契数列
纯粹的递归版
/** * 单纯的进行递归操作效率及其低下,因为算法内部做了大量的重复计算,时间复杂度为O(2^n) */ function fibonacci(n) { if (n <= 1) { return n; } else { return fibonacci(n - 1) + fibonacci(n - 2); } }
带缓存的递归版
/** * 将计算好的结果缓存起来,这样可以避免重复计算,时间复杂度为O(n) */ const memory = [0, 1]; function fibonacci(n) { if (typeof memory[n] === 'number') { return memory[n]; } else { const result = fibonacci(n - 1) + fibonacci(n - 2); memory[n] = result; return result; } }
循环版
-
实现函数节流
/** * 函数节流 * @param {function} func 需要节流的函数 * @param {number} interval 函数的执行间隔(毫秒) * @param {object} options { leading: true, tailing: false } */ function throttle(func, interval, options) { let canRun = false, // 是否可以执行函数 lastInvokeTime = 0, // 函数上一次被执行的时刻(时间戳) tid = null; // 定时器id,设置间隔过后再次执行一次函数 // leading和tailing不能同时为false const { leading = true, tailing = false } = options || {}; const throttled = function throttled(...args) { let now = Date.now(); if (!lastInvokeTime) { if (leading) { canRun = true; } } else { if (now - lastInvokeTime >= interval) { canRun = true; } } if (canRun) { if (tid) { clearTimeout(tid); tid = null; } canRun = false; lastInvokeTime = now; func.apply(this, args); } else if (!tid && tailing) { tid = setTimeout(function () { func.apply(this, args); lastInvokeTime = 0; tid = null; }, now - lastInvokeTime); } } /** * 取消最后一次的函数执行 */ throttled.cancel = function cancel() { lastInvokeTime = 0; if (tid) { clearTimeout(tid); tid = null; } } return throttled; } // test let count = 0; function increment() { count += 1; console.log((new Date().getSeconds()), count); } const incrementThrottled = throttle(increment, 3000); while (count < 5) { incrementThrottled(); } // test result // 47 1 // 50 2 // 53 3 // 56 4 // 59 5
-
利用reduce方法实现map方法
/** * 利用reduce方法实现map方法 * @param {function} callback map回调函数 * @param {object} context callback执行时的this上下文对象 */ Array.prototype.mapImplementedByReduce = function (callback, context = null) { const reducer = function (accumulator, currentValue, index, array) { const result = callback.call(context, currentValue, index, array); accumulator.push(result); return accumulator; } return this.reduce(reducer, []); } /** * test */ const arr = [1, 3, 5]; const callback = function (number, index, array) { return Math.pow(number, 3); } console.log(arr.mapImplementedByReduce(callback)); // [ 1, 27, 125 ]
-
redux源代码阅读
Redux是一个常用的组件状态管理库,通过将应用的状态数据集中存储并且限制可以更改状态数据的路径,使得开发者可以更好的追踪以及预测应用状态的变化过程,Redux的源代码不到1000行,是一个学习源代码分析的不错对象.
在浏览器中通过
script
标签加载后,脚本会在全局作用域下添加Redux
变量.对应的源代码如下
/** * 先探测脚本所处的运行环境和加载机制,然后将redux的方法和属性挂载到对应的作用域 * 1. Node.js环境下和AMD加载机制下挂载到模块的导出对象 * 2. script标签加载挂载到window对象 */ (function (global, factory) { // Node.js环境 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : // 浏览器环境(通过AMD方式加载) typeof define === 'function' && define.amd ? define(['exports'], factory) : // 浏览器环境(通过script标签加载) (global = global || self, factory(global.Redux = {})); }(this, function (exports) { /* other code... */ exports.__DO_NOT_USE__ActionTypes = ActionTypes; exports.applyMiddleware = applyMiddleware; exports.bindActionCreators = bindActionCreators; exports.combineReducers = combineReducers; exports.compose = compose; exports.createStore = createStore; Object.defineProperty(exports, '__esModule', { value: true }); }));
__DO_NOT_USE__ActionTypes
-
HTTP缓存策略
一般来说,对于html, css, js以及图片等静态资源文件,浏览器会进行缓存,这样下次访问这些资源的时候就可以直接从缓存获取,从而提升页面的加载速度,但是浏览器的缓存机制遵循一定的策略.
什么情况下会缓存?
如果希望资源被浏览器缓存到本地,需要满足以下条件:
- http响应头Content-type必须标明当前资源是可被缓存的静态资源,例如text/html, application/javascript, text/css, image/png等等
- http响应头Cache-Control指明了该资源允许被缓存
与缓存有关的HTTP请求头和响应头?
-
前端优化路径图
微博上看到的关于前端优化的图
-
js中的in操作符和Object.keys方法
in操作符
in
和typeof
一样,只是操作符,不是函数,它用来判断对象是否拥有某个属性,例如:console.log('alert' in window); // true console.log('xxoo' in window); // false
在js中,对象的属性查找和继承是基于原型链来实现的,可以使用
hasOwnProperty
方法判断一个属性是属于对象本身,还是属于它的上层原型:console.log(window.hasOwnProperty('alert')); // true console.log(([]).hasOwnProperty('slice')); // false
-
洗牌算法
洗牌算法,用于随机打乱一个有限列表内的元素顺序,目前公认最好的洗牌算法就是Fisher-Yates算法,使用JavaScript实现Fisher-Yates算法对一个数组进行顺序打乱的代码如下.
/** * Fisher-Yates算法 * 将数组元素的顺序原地打乱 * 时间复杂度O(N) * @param {Array<any>} 数组 */ function shuffle(arr) { for (let i = arr.length - 1; i > 0; i--) { const idx = Math.floor(Math.random() * (i + 1)); const tmp = arr[i]; arr[i] = arr[idx]; arr[idx] = tmp; } }