什麼是面向切面編程?vue
Function.prototype.before = function (beforefn) {
let _self = this; // 緩存原函數的引用
return function () { // 代理函數
beforefn.apply(this, arguments); // 執行前置函數
return _self.apply(this, arguments); // 執行原函數
}
}
Function.prototype.after = function (afterfn) {
let _self = this;
return function () {
let set = _self.apply(this, arguments);
afterfn.apply(this, arguments);
return set;
}
}
let func = () => console.log('func');
func = func.before(() => {
console.log('===before===');
}).after(() => {
console.log('===after===');
});
func();
複製代碼
輸出結果:node
===before===
func
===after===
複製代碼
const factorial1 = n => {
if (n <= 1) return 1
return n * factorial1(n - 1)
}
// 尾遞歸優化
const factorial2 = (n, total = 1) => {
if (n <= 1) return total
return factorial2(n - 1, total * n)
}
console.log(factorial1(3)) // 6
console.log(factorial2(3)) // 6
console.log(factorial1(5)) // 120
console.log(factorial2(5)) // 120
複製代碼
//循環不變式 guess 等於l r中間位置
const bsearch = (A, x) => {
let l = 0
let r = A.length - 1
let guess
while (l <= r) {
console.log('find')
guess = Math.floor((l + r) / 2)
if (A[guess] === x) return guess
if (A[guess] > x) r = guess - 1
else l = guess + 1
}
return -1
}
let arr = [1, 2, 3, 4, 5, 6, 7, 8]
console.log(bsearch(arr, 6)) // 5
複製代碼
斐波那契數列從第三項開始,每一項都等於前兩項之和。指的是這樣一個數列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 …git
獲得數列中第n項指向的數值是多少es6
1.遞歸github
function fib(n) {
if (n === 1 || n === 2) return n - 1;
return fib(n - 1) + fib(n - 2)
}
console.log(fib(10)); // 34
複製代碼
時間複雜度爲O(2^n)web
2.非遞歸面試
function fib(n) {
let a = 0;
let b = 1;
let c = a + b;
for (let i = 3; i < n; i++) {
a = b;
b = c;
c = a + b;
}
return c;
}
console.log(fib(10)); // 34
複製代碼
時間複雜度爲O(n)正則表達式
const Stack = (() => {
const wm = new WeakMap()
class Stack {
constructor() {
wm.set(this, [])
this.top = 0
}
push(...nums) {
let list = wm.get(this)
nums.forEach(item => {
list[this.top++] = item
})
}
pop() {
let list = wm.get(this)
let last = list[--this.top]
list.length = this.top
return last
}
peek() {
let list = wm.get(this)
return list[this.top - 1]
}
clear() {
let list = wm.get(this)
list.length = 0
}
size() {
return this.top
}
output() {
return wm.get(this)
}
isEmpty() {
return wm.get(this).length === 0
}
}
return Stack
})()
let s = new Stack()
s.push(1, 2, 3, 4, 5)
console.log(s.output()) // [ 1, 2, 3, 4, 5 ]
複製代碼
function divideBy2(decNumber, base = 2) {
let remStack = new Stack()
let rem
let binaryString = ''
let digits = '0123456789ABCDEF'
while (decNumber > 0) {
rem = Math.floor(decNumber % base)
remStack.push(rem)
decNumber = Math.floor(decNumber / base)
}
while (!remStack.isEmpty()) {
binaryString += digits[remStack.pop()].toString()
}
return binaryString
}
// 將十進制轉換成其餘進制
let num = 100345
num.toString(2) // "11000011111111001"
num.toString(8) // "303771"
console.log(divideBy2(num, 2)) // "11000011111111001"
console.log(divideBy2(num, 8)) // "303771"
複製代碼
// 類數組
let obj = {
'1': 'a',
'2': 'b',
length: 2,
push: Array.prototype.push
};
// Array.prototype.push.call(obj, 'c');
obj.push('c')
console.log(obj); // { '1': 'a', '2': 'c', length: 3 }
複製代碼
Array的push底層實現是依賴於 數組的length屬性的算法
Array.prototype.push2 = function(...rest){
this.splice(this.length, 0, ...rest)
return this.length;
}
複製代碼
對於 pop也是同樣npm
Array.prototype.pop2 = function(){
return this.splice(this.length - 1, 1)[0];
}
複製代碼
function fn(num = 0, ary = []) {
for (let i = 0; i < ary.length; i++) {
let diff = num - ary[i];
let diffIndex = ary.indexOf(diff);
if (diffIndex !== -1 && diffIndex !== i) {
return [i, diffIndex];
}
}
return false;
}
let num = 3;
let arr = [-1, 4, 6, 2];
console.log(fn(num, arr)); // [0, 1]
複製代碼
function mergeAry(left = [], right = []) {
const result = [];
while (left.length && right.length) {
result.push(left[0] <= right[0] ? left.shift() : right.shift());
}
return result.concat(left, right);
}
console.log(mergeAry([1, 2, 3], [1, 4, 8, 9])); // [ 1, 1, 2, 3, 4, 8, 9 ]
複製代碼
如:
[1, 18, 3, 2] => 1 + 2 = 3 => true;
[3, 11, 2, 7] => false
let a1 = [2, 99, 3, 5]
let a2 = [1, 2, 10, 5]
function find(arr) {
arr.sort((a, b) => a - b)
for (let i = 0; i < arr.length - 1; i++) {
let cur = arr[i]
for (let k = i + 1; k < arr.length; k++) {
let next = arr[k]
let diff = next - cur
if (![cur, next].includes(diff) && arr.includes(diff)) {
return true
}
}
}
return false
}
console.log(find(a1)) // true
console.log(find(a2)) // false
複製代碼
// 原生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));
複製代碼
/**
* new2 new關鍵字的代碼實現演示
* @param {function} func 被new的類 (構造函數)
*/
function new2(func) {
// 建立了一個實例對象 o,而且這個對象__proto__指向func這個類的原型對象
let o = Object.create(func.prototype);
// (在構造函數中this指向當前實例)讓這個類做爲普通函數值行 而且裏面this爲實例對象
let k = func.call(o);
// 最後再將實例對象返回 若是你在類中顯示指定返回值k,
// 注意若是返回的是引用類型則將默認返回的實例對象o替代掉
return typeof k === 'object' ? k : o;
}
// 實驗
function M() { // 即將被new的類
this.name = 'liwenli';
}
let m = new2(M); // 等價於 new M 這裏只是模擬
console.log(m instanceof M); // instanceof 檢測實例
console.log(m instanceof Object);
console.log(m.__proto__.constructor === M);
複製代碼
let obj = { a: 1};
function fn() {
this.b = 100;
return this.a;
}
let fe = fn.bind(obj);
console.log(fe()); // 1 裏面this是obj
console.log(obj); // { a: 1, b: 100 }
console.log(new fe()); // 裏面this是當前建立實例對象 { b: 100 }
複製代碼
let obj1 = {id: 1};
Object._create = (o) => {
let Fn = function() {}; // 臨時的構造函數
Fn.prototype = o;
return new Fn;
}
let obj2 = Object._create(obj1);
console.log(obj2.__proto__ === obj1); // true
console.log(obj2.id); // 1
// 原生的Object.create
let obj3 = Object.create(obj1);
console.log(obj3.__proto__ === obj1); // true
console.log(obj3.id); // 1
複製代碼
function CodingMan(name) { // 主要考察的是 面向對象以及JS運行機制(同步 異步 任務隊列 事件循環)
function Man(name) {
setTimeout(() => { // 異步
console.log(`Hi! This is ${name}`);
}, 0);
}
Man.prototype.sleep = function(time) {
let curTime = new Date();
let delay = time * 1000;
setTimeout(() => { // 異步
while (new Date() - curTime < delay) {} // 阻塞當前主線程
console.log(`Wake up after ${time}`);
}, 0);
return this;
}
Man.prototype.sleepFirst = function(time) {
let curTime = new Date();
let delay = time * 1000;
while (new Date() - curTime < delay) {} // 阻塞當前主線程
console.log(`Wake up after ${time}`);
return this;
}
Man.prototype.eat = function(food) {
setTimeout(() => { // 異步
console.log(`Eat ${food}~~`);
}, 0)
return this;
}
return new Man(name);
}
// CodingMan('Peter');
// CodingMan('Peter').sleep(3).eat('dinner');
// CodingMan('Peter').eat('dinner').eat('supper');
// CodingMan('Peter').sleepFirst(5).eat('supper');
複製代碼
function CodingMan(name) {
function fe() {
fe.flag = true;
console.log(`Hi! This is ${name}`);
}
fe.flag = false;
fe.timer = setTimeout(() => {
clearTimeout(fe.timer);
if (!fe.flag) fe();
}, 0);
return fe;
}
Function.prototype.sleep = function (delay) {
this()
this.await(delay);
return this;
}
Function.prototype.sleepFirst = function (delay) {
this.await(delay);
this();
return this;
}
Function.prototype.eat = function (dinner) {
setTimeout(() => {
console.log(`Eat ${dinner}~`);
});
return this;
};
Function.prototype.await = function (delay) {
delay = isNaN(delay) ? 0 : delay;
let startTime = new Date();
let delayTime = delay * 1000;
while (new Date() - startTime <= delayTime) {
}
console.log(`Wake up after ${delayTime}ms`);
}
// CodingMan('peter')
// CodingMan('peter').sleep(2).eat('hanbao');
// CodingMan('peter').sleepFirst(2).eat('hanbao');
CodingMan('peter').eat('haha').eat('hanbao');
複製代碼
function add(a, b, c) {
return a + b + c;
}
let f1 = add.bind(undefined, 100);
console.log(f1(2, 3)); // 105 = 100 + 2 + 3
let f2 = f1.bind(undefined, 200);
console.log(f2(3)); // 303 = 100 + 200 + 3
複製代碼
知識點:對象的valueOf瀏覽器環境下 隱式轉化爲基本數據類型(一元操做符+object/字符串拼接 ''+object)時,會調用自身的valueOf方法取值,若是自身也存在toString方法 先調用valueOf 若是valueOf返回值不是基本數據類型 則調用toString, toString的返回值也不是基本數據類型就報錯。
valueOf調用場景
let obj = { x: 1, y: 2 };
obj.toString = function() {
return this.x + this.y;
}
obj.valueOf = function() {
return this.x + this.y + 100;
}
// 如下狀況下自身valueOf被調用
console.log('' + obj); // 103
console.log(+obj); // 103
複製代碼
function fn() {};
fn.valueOf = () => console.log('valueof');
console.log(fn); // valueof
複製代碼
const mul = x => {
const result = y => mul(x * y); // 遞歸調用mul
result.valueOf = () => x;
return result;
}
console.log(mul(2)(3)); // 6
// 在上面mul每執行一次,就會返回一個valueOf被改寫後的新函數result 而且result執行會在裏面調用mul(x * y)
// 在result函數的valueOf裏保存着 由上一次x * y 傳進來的結果x, 也就是上一次x*y 會做爲這一次的輸出 依然叫x
// 第一次mul(2) 此時 x爲2 return result
result 爲 result = y => mul(2 * y);
// 第二次 mul(2)(3) 等價於 第一個mul返回的result(3), result執行 => mul(2 * 3) 再次調用mul 將2*3 = 6 的結果做爲mul參數
// 最後mul(6) x = 6 在返回一個新函數result 此時result的valueOf = () => 6
// log(mul(2)(3)) 至關於log的最後返回的result 隱式調用valueOf 返回 6
複製代碼
function fe(a, b, c) {
return a + b + c;
}
function curry(fe) {
let args = []; // 參數集合
let len = args.length;
return function bar() {
args = [...args, ...arguments]; // 收集參數
if (args.length >= fe.length) {
return fe.apply(this, args);
}
return bar;
}
}
console.log(curry(fe)(1)(2)(3)); // 6
複製代碼
// currying 函數柯理化
let currying = function(fn) {
let args = [];
return function fe() {
if (arguments.length === 0) {
return fn.apply(this, args);
}
[].push.apply(args, arguments);
return fe;
}
}
let count = currying(function (...rest) {
return rest.reduce((prev, cur) => prev + cur, 0);
});
console.log(count(100)(200)(10)()); // 310
複製代碼
// 參數收集 指定次數後執行
function fn(...rest) {console.log(rest);};
function after(fn, time = 1) {
let params = [];
return function(...rest) {
params = [...params, ...rest];
if (--time === 0) {
fn.apply(this, params);
}
}
}
let newFn = after(fn, 3); // 執行3次 內部fn纔會執行
newFn(2);
newFn(3);
newFn(4);
複製代碼
throttle 策略的電梯。保證若是電梯第一我的進來後,50毫秒後準時運送一次,不等待。若是沒有人,則待機。
let throttle = (fn, delay = 50) => { // 節流 控制執行間隔時間 防止頻繁觸發 scroll resize mousemove
let stattime = 0;
return function (...args) {
let curTime = new Date();
if (curTime - stattime >= delay) {
fn.apply(this, args);
stattime = curTime;
}
}
}
複製代碼
// 同時包含 數字 字母大小寫
// let reg = /^(?!([a-zA-Z]+|\d+)$)[a-zA-Z\d]{8,15}$/
// ^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]
let reg = /^(?!([a-zA-Z]+|[a-z\d]+|[A-Z\d]+)$)[a-zA-Z\d]{8,15}$/
console.log(reg.test('lolABC123')) // true
console.log(reg.test('lol12313123')) // false
console.log(reg.test('ADF12313123')) // false
console.log(reg.test('12312313123')) // false
console.log(reg.test('LLLLLLLLLL')) // false
console.log(reg.test('aaaaaaass')) // fals
複製代碼
/**
* @desc 函數防抖
* @param func 函數
* @param wait 延遲執行毫秒數
* @param immediate true 表當即執行,false 表非當即執行
*/
function debounce(func,wait,immediate) {
var timeout;
return function () {
var context = this;
var args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
複製代碼
debounce 策略的電梯。若是電梯裏有人進來,等待50毫秒。若是又人進來,50毫秒等待從新計時,直到50毫秒超時,開始運送。
let debounce = (fn, time = 50) => { // 防抖動 控制空閒時間 用戶輸入頻繁
let timer;
return function (...args) {
let that = this;
clearTimeout(timer);
timer = setTimeout(fn.bind(that, ...args), time);
}
}
複製代碼
function deepCopy(obj) {
if (typeof obj !== 'object') return obj;
if (typeof window !== 'undefined' && window.JSON) { // 瀏覽器環境下 並支持window.JSON 則使用 JSON
return JSON.parse(JSON.stringify(obj));
} else {
let newObj = obj.constructor === Array ? [] : {};
for(let key in obj) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
return newObj;
}
}
let obj = {a: 1, b: [12]};
let newObj = deepCopy(obj);
newObj.b[1] = 100;
console.log(obj);
console.log(newObj);
複製代碼
function cloneDeep(obj) {
let type = isType(obj)
if (type === 'Array' || type === 'Object') {
return cloneObj(obj)
} else if (type === 'Date') {
return obj.constructor(obj)
} else {
return obj
}
}
function cloneObj(obj) {
let newObj = obj instanceof Array ? [] : {};
for (let key in obj) {
newObj[key] = typeof obj[key] === 'object' ? cloneObj(obj[key]) : obj[key]
}
return newObj;
}
function isType(o) {
return /\[object\s(.*?)\]/.exec(Object.prototype.toString.call(o))[1]
}
let fn = function () {
return 123
}
var a = [[1, 2, 3], [4, 5, 6, 7, fn]];
// let c = new Date();
// var b = cloneDeep(c);
var b = cloneDeep(a);
console.log(b[0], a[0]);
console.log(b[0] === a[0]);
複製代碼
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
複製代碼
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
複製代碼
1.es5
Function.prototype._bind = function(context) {
let func = this;
let params = [].slice.call(arguments, 1);
let Fnop = function() {};
let fbound = function() {
params = params.concat([].slice.call(arguments, 0));
return func.apply(this instanceof Fnop ?
this : context, params);
}
Fnop.prototype = this.prototype;
fbound.prototype = new Fnop();
return fbound;
}
function foo() {
this.b = 100;
return this.a;
}
let fe = foo._bind({ a: 1 });
console.log(fe()); // 1
console.log(new fe()); // 實例 {b: 100}
2.es6
Function.prototype.mybind = function(context, ...rest) {
return (...params) => this.call(context, ...rest, ...params);
}
複製代碼
// 組合串聯
let fn1 = (a) => a + 1;
let fn2 = (b) => b + 2;
let fn3 = (c) => c + 3;
let funs = [fn1, fn2, fn3];
let compose = (func) => {
return arg => func.reduceRight((composed, fn) => fn(composed), arg);
}
console.log(compose(funs)(100)); // 至關於fn1(fn2(fn3(100)))
複製代碼
redux 源碼中compose實現(github.com/reduxjs/red…)
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
複製代碼
koa-compose 實現
function compose(middleware) {
return function(ctx, next) {
let index = -1;
return dispatch(0)
function dispatch(i) {
if(i <= index) return Promise.reject(new Error('next() called multiple times'));
index = i;
let fn = middleware[i]
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
try {
return Promise.resolve(fn(ctx, dispatch.bind(null, i + 1)))
} catch(e) {
return Promise.reject(e)
}
}
}
}
let mid1 = (ctx, next) => {
console.log('ctx1', ctx);
next()
}
let mid2 = (ctx, next) => {
console.log('ctx2', ctx);
next()
}
let mid3 = (ctx, next) => {
console.log('ctx3', ctx);
}
let co = compose([mid1, mid2, mid3])
co('ctx')
複製代碼
function *fn(a = 0) {
console.log('a', a)
const b = yield 2
console.log('b', b)
const c = yield Promise.resolve(3)
console.log('c', c)
return a + b + c
}
// const it = fn(1)
// it.next()
// it.next(2)
// it.next(3)
// co(fn, 1)
function fe() {
return 100
}
run(fn, 10).then(res => {
console.log(res)
})
function run(gen) {
const slice = [].slice
const args = slice.call(arguments, 1)
return new Promise((resolve, reject) => {
const ite = (typeof gen === 'function') && gen.apply(this, args)
if (!ite || typeof ite.next !== 'function') return resolve(ite)
function next(res) {
const { value, done } = ite.next(res)
if (done) {
resolve(value)
} else if (value instanceof Promise) {
value.then(next)
} else {
next(value)
}
}
next()
})
}
複製代碼
class Promise {
constructor(fn) {
this.status = 'Pending'
setTimeout(() => {
fn((data) => {
this.resolve(data)
}, (error) => {
this.reject(error)
})
})
}
resolve(data) {
if (this.status === 'Pending') {
this.success(data)
this.status = 'Fulfilled'
}
}
reject(error) {
if (this.status === 'Pending') {
this.error(error)
this.status = 'Rejected'
}
}
then(success, error) {
this.success = success
this.error = error
}
}
let p1 = new Promise((resolve, reject) => {
// reject('hello error');
setTimeout(() => {
resolve('hello promise')
}, 1000)
})
p1.then((data) => console.log(data), (err) => console.log(err))
複製代碼
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
// 中斷後續調用
複製代碼
// promisify.js
module.exports = {
promisify(fn){
return function () {
var args = Array.from(arguments);
return new Promise(function (resolve, reject) {
fn.apply(null, args.concat(function (err) {
if (err) {
reject(err);
} else {
resolve(arguments[1])
}
}));
})
}
}
}
// main.js
const fs = require('fs');
const {promisify} = require('./promisify.js');
const readFile = promisify('fs.readFile'); // 轉換異步讀取
// 異步文件 由回調函數形式變成promise形式
readFile('./1.txt', 'utf8').then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
複製代碼
window._requestAnimationFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
複製代碼
let str = 'My age is 0, 0 si ega ym.';
方法一
function palindrome(params) {
params = params.replace(/[\W\s_]/ig, '');
return params.toLowerCase() === params.split('').reverse().join('').toLowerCase();
}
console.log(palindrome(str));
方法二
function palindrome(params) {
params = params.replace(/[\W\s_]/ig, '').toLowerCase();
for (var i = 0, j = params.length-1; i<j; i++, j--) {
if (params[i] !== params[j]) {
return false;
}
}
return true;
}
複製代碼
// 將 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);
}
}
複製代碼
將[[1, 2], 3, [[[4], 5]]] 展平爲 [1, 2, 3, 4, 5]
let arr = [[1, 2], 3, [[[4], 5]]]; // 數組展平
function flatten(arr) {
return [].concat(
...arr.map(x => Array.isArray(x) ? flatten(x) : x)
)
}
複製代碼
const arr = [1, 2, 3, 4, 5, 6, 7, 8];
// 二分查找 遞歸 由中間開始往兩邊查找 前提是有序的數組 返回對應的索引位置
function binarySearch1(arr, dest, start = 0, end = data.length) {
if (start > end) {
return -1
}
let midIndex = Math.floor((start + end) / 2); // 中間位置索引
let mid = arr[midIndex]; // 中間值
if (mid == dest) {
return midIndex;
}
if (dest < mid) { // 要找的比中間值小 就從中間往開頭找 一直到0
return binarySearch1(arr, dest, 0, midIndex - 1);
}
if (dest > mid) { // 要找的比中間值大 就從中間日後找 一直到end結束
return binarySearch1(arr, dest, midIndex + 1, end);
}
return -1; // 找不到返回-1
}
console.log(binarySearch1(arr, 7, 3, 6)); // 6
// 非遞歸 arr前提有序數組 (從小到大)返回對應的索引位置
function binarySearch2(arr, dest) {
let max = arr.length - 1;
let min = 0;
while (min <= max) {
let mid = Math.floor((max + min) / 2); // mid中間位置索引
if (dest < arr[mid]) { // 若是要找的這項比中間項還要小 說明應該在mid中間位置前面 修改最大邊界值max=mid-1
max = mid - 1;
} else if (dest > arr[mid]) { // 若是要找的這項比中間項還要大 說明應該在mid中間位置的後面 修改最小邊界值min=mid+1
min = mid + 1;
} else {
return mid;
}
}
return -1; // 找不到返回-1
}
console.log(binarySearch2(arr, 3)); // 2
複製代碼
在一個二維數組中,每一行都按照從左到右遞增,每一列都從上到下遞增的順序排序,完成一個函數,輸入這個二維數組和一個整數,判斷數組中是否含有該整數
思路是同樣的,只不過從一維變成了二維,咱們遍歷思路能夠這樣子:
循環以上步驟
function findTarget(arr,target) {
let i = 0; // i表明行
let j = arr[i].length -1; // j每行中每項索引位置 從最後項開始比較
while(i < arr.length && j>=0) {
if(target < arr[i][j]) {
j--;
} else if (target > arr[i][j]) {
i++;
} else {
return `找到了,位置在${i},${j}`
}
}
return `(${i},${j})`
}
let arr = [
[1,2,3,4],
[5,9,10,11],
[13,20,21,23]
] //測試
複製代碼
// 例如:[1,2,4,4,3,3,1,5,3]
// 輸出:[1,3,4]
let arr = [1, 2, 4, 4, 3, 3, 1, 5, 3];
// 方法一
function repeat1(arr){
var result = [], map = {};
arr.map(function(num){
if(map[num] === 1) result.push(num); // 等於1說明以前出現過一次 此次重複出現了
map[num] = (map[num] || 0) + 1; // 微妙之處 開始第一次出現無值 記爲 0 + 1 = 1 下一次從1開始累加
});
return result;
}
console.log(repeat1(arr));
// 方法二
function repeat(arr) {
let result = arr.filter((x, i, self) => {
return self.indexOf(x) === i && self.lastIndexOf(x) !== i
}); //
return result;
}
console.log(repeat(arr));
複製代碼
// 若是次數相同 則按照值排序 好比 2, 2, 2和 1, 1, 1 應排序爲 [1, 1, 1, 2, 2, 2]
// 好比 [1, 2, 1, 2, 1, 3, 4, 5, 4, 5, 5, 2, 2] => [3, 4, 4, 1, 1, 1, 5, 5, 5, 2, 2, 2, 2]
const repeatTimeSort = arr => {
arr.sort((a, b) => a - b)
let ary = []
while (arr.length > 0) {
let a = arr[0]
let start = arr.indexOf(a)
let end = arr.lastIndexOf(a) + 1
ary.push(arr.splice(start, end - start))
}
ary.sort((a, b) => a.length - b.length)
return ary.reduce((prev, cur) => prev.concat(cur), [])
}
// [ 12, 13, 13, 11, 11, 11 ]
console.log(repeatTimeSort([11, 12, 13, 11, 11, 13]))
// [ 3, 4, 4, 1, 1, 1, 5, 5, 5, 2, 2, 2, 2 ]
console.log(repeatTimeSort([1, 2, 1, 2, 1, 3, 4, 5, 4, 5, 5, 2, 2]))
複製代碼
// 方法一 遞歸寫法
function createArray(len, arr = []) {
if (len > 0) {
arr[--len] = len;
createArray(len, arr);
}
return arr;
}
console.log(createArray(100));
// 方法二
// 下面評論中@MaDivH 提供的實現方法 長度爲 100 的數組
Array(100).fill().map((_,i)=>i+1);
// 方法三
[...Array(100).keys()]
複製代碼
const roles = [
{ id: 1, name: 'a', parentId: 0},
{ id: 2, name: 'b', parentId: 0},
{ id: 3, name: 'c', parentId: 1},
{ id: 4, name: 'd', parentId: 1},
{ id: 5, name: 'e', parentId: 2},
{ id: 6, name: 'f', parentId: 2}
]
// const output = [{
// id: 1,
// name: 'a',
// parentId: 0,
// children: [
// { id: 3, name: 'c', parentId: 1, children: [] },
// { id: 4, name: 'd', parentId: 1, children: [] }
// ]
// },
// {
// id: 2,
// name: 'b',
// parentId: 0,
// children: [
// { id: 5, name: 'e', parentId: 2 },
// { id: 6, name: 'f', parentId: 2 }
// ]
// }
// ]
function convert(roles) {
const root = []
const dict = {}
roles.forEach(item => {
if (item.parentId === 0) {
root.push(item)
}
item.children = []
dict[item.id] = item
})
roles.forEach(item => {
if (item.parentId !== 0) {
dict[item.parentId].children.push(item)
}
})
return root
}
console.log(convert(roles))
複製代碼
var docs = [
{
id: 1,
words: ['hello', "world"]
}, {
id: 2,
words: ['hello', "hihi"]
}, {
id: 3,
words: ['haha', "hello"]
}, {
id: 4,
words: ['world', "nihao"]
}
];
findDocList(docs, ['hello']) // 文檔id1,文檔id2,文檔id3
findDocList(docs, ['hello', 'world']) // 文檔id1
function findDocList(docs, word = []) {
if (word.constructor !== Array) return;
let ids = [];
for (let i = 0; i < docs.length; i++) {
let {id, words} = docs[i];
let flag = word.every((item) => {
return words.indexOf(item) > -1;
});
flag && ids.push(id);
}
return ids;
}
findDocList(docs, ['hello', 'world']);
複製代碼
const permute = function(nums) {
if (nums.length <= 1) return [nums]
const permutes = []
for (let i = 0; i < nums.length; i++) {
const num = nums[i]
const others = nums.slice(0, i).concat(nums.slice(i + 1))
const list = permute(others)
list.forEach(item => {
permutes.push([num].concat(item))
})
}
return permutes
};
const arr = [1, 2, 3]
console.log(permute(arr))
複製代碼
function getByClass(cName) {
if ('getElementsByClassName' in this) {
return this.getElementsByClassName(cName);
}
cName = cName.replace(/(^\s+|\s+$)/g, '').split(/\s+/g);
let eles = this.getElementsByTagName('*');
for (let i = 0; i < cName.length; i++) {
let reg = new RegExp(`(^| )${cName[i]}( |$)`);
let temp = [];
for (let j = 0; j < eles.length; j++) {
let cur = eles[j];
let {className} = cur;
if (reg.test(className)) {
temp.push(cur);
}
}
eles = temp;
}
return eles;
}
console.log(content.getByClass('c1 c2 '));
複製代碼
插入排序 從後往前比較 直到碰到比當前項 還要小的前一項時 將這一項插入到前一項的後面
function insertSort(arr) {
let len = arr.length;
let preIndex, current;
for (let i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i]; // 當前項
while (preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex]; // 若是前一項大於當前項 則把前一項日後挪一位
preIndex-- // 用當前項繼續和前面值進行比較
}
arr[preIndex + 1] = current; // 若是前一項小於當前項則 循環結束 則將當前項放到 前一項的後面
}
return arr;
}
複製代碼
function insert(arr, i, x) {
let prev = i - 1;
while(prev >= 0 && arr[prev] > x) {
arr[prev + 1] = arr[prev];
prev--;
}
arr[prev + 1] = x;
}
function insert_sort(arr) {
for (let i = 1; i < arr.length; i++) {
insert(arr, i, arr[i]);
}
return arr;
}
console.log(insert_sort([1, 10, 3, 0]));
複製代碼
選擇排序 每次拿當前項與後面其餘項進行比較 獲得最小值的索引位置 而後把最小值和當前項交換位置
function selectSort(arr) {
let len = arr.length;
let temp = null;
let minIndex = null;
for (let i = 0; i < len - 1; i++) { // 把當前值的索引做爲最小值的索引一次去比較
minIndex = i; // 假設當前項索引 爲最小值索引
for (let j = i + 1; j < len; j++) { // 當前項後面向一次比小
if (arr[j] < arr[minIndex]) { // 比假設的值還要小 則保留最小值索引
minIndex = j; // 找到最小值的索引位置
}
}
// 將當前值和比較出的最小值交換位置
if (i !== minIndex) {
temp = arr[i]
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
return arr;
}
複製代碼
冒泡排序 相鄰兩項進行比較 若是當前值大於後一項 則交換位置
function swap(arr, i, j) {
[arr[i], arr[j]] = [arr[j], arr[i]]
}
function bubleSort(arr) {
let length = arr.length;
let temp = null;
for (let i = 0; i < length - 1; i++) { // 控制輪數
let flag = false; // 當前這輪是否交換過標識
for (let l = 0; l < length - i - 1; l++) { // 控制每輪比較次數
if (arr[l] > arr[l + 1]) {
// temp = arr[l];
// arr[l] = arr[l + 1];
// arr[l + 1] = temp;
swap(arr, l, l + 1);
flag = true; // 若是發生過交換flag則爲true
}
}
if (!flag) { // 優化 若是從頭至尾比較一輪後 flag依然爲false說明 已經排好序了 不必在繼續下去
temp = null;
return arr;
}
}
return arr;
}
複製代碼
function swap(arr, i, j) {
[arr[i], arr[j]] = [arr[j], arr[i]]
}
function bubble_sort(arr) {
for (let i = arr.length - 1; i >= 1; i--) {
for (let j = 1; j <= i; j++) {
arr[j - 1] > arr[j] && swap(arr, j - 1, j)
}
}
return arr;
}
console.log(bubble_sort([1, 10, 3, 0]));
複製代碼
function quickSort(arr) {
if (arr.length <= 1) return arr;
let midIndex = Math.floor(arr.length / 2);
let midNum = arr.splice(midIndex, 1)[0];
let left = [];
let right = [];
for(let i = 0; i < arr.length; i++) {
let cur = arr[i];
if (cur <= midNum) {
left.push(cur);
} else {
right.push(cur);
}
}
return quickSort(left).concat(midNum, quickSort(right));
}
let arr = [2, 4, 12, 9, 22, 10, 18, 6];
quickSort(arr);
複製代碼
let array = [9, 6, 20, 3, 2];
// let array = [15, 13, 20, 21, 29];
function quickSort(arr, left = 0, right = arr.length - 1) {
let len = arr.length;
let partitionIndex;
// left = typeof left != 'number' ? 0 : left;
// right = typeof right != 'number' ? len - 1 : right;
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) {
let pivot = left;
let index = pivot + 1;
for (let i = index; i <= right; i++) {
if (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
swap(arr, pivot, index - 1);
return index - 1;
}
function swap(arr, i, index) {
[arr[i], arr[index]] = [arr[index], arr[i]];
}
console.log(quickSort(array));
複製代碼
let array = [5, 13, 20, 3, 2];
// let array = [15, 13, 20, 21, 29];
function mergeSort(array) {
let arr = array.slice(0);
let len = arr.length;
if (len < 2) {
return arr;
}
let midIndex = Math.floor(len / 2);
let left = arr.slice(0, midIndex);
let right = arr.slice(midIndex);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
let result = [];
while(left.length && right.length) {
result.push(left[0] < right[0] ? left.shift() : right.shift());
}
if (left.length && !right.length) {
result = result.concat(left);
}
if (right.length && !left.length) {
result = result.concat(right);
}
return result;
}
console.log(mergeSort(array));
複製代碼
const arr = [1, 2, 1, 2, 3, 4, 2, 1, 3];
// 1 ES6
let newArr = [...new Set(arr)];
// 2
const arr = [1, 2, 1, 2, 3, 4, 'l', 2, 1, 3, 'l'];
const newArr = arr.filter(function(ele, index, array) {
return index === array.indexOf(ele)
});
console.log(newArr); // [ 1, 2, 3, 4, 'l' ]
// 3
Array.prototype.unique2 = function() {
let newArr = [];
let len = this.length;
for(let i = 0; i < len; i++) {
let cur = this[i];
if(newArr.indexOf(cur) === -1) {
newArr[newArr.length] = cur;
}
}
return newArr;
}
console.log(arr.unique1());
// 4
Array.prototype.unique3 = function() {
let newArr = this.slice(0);
let len = this.length;
let obj = {};
for(let i = 0; i < len; i++) {
let cur = newArr[i];
if(obj[cur]) {
newArr[i] = newArr[newArr.length - 1];
newArr.length--;
i--;
continue;
}
obj[cur] = cur;
}
return newArr;
}
console.log(arr.unique3());
// 5
Array.prototype.unique4 = function() {
let json = {}, newArr = [], len = this.length;
for(var i = 0; i < len; i++) {
let cur = this[i];
if (typeof json[cur] == "undefined") {
json[cur] = true;
newArr.push(cur)
}
}
return newArr;
}
console.log(arr.unique4());
複製代碼
// 處理數字
let str1 = 2123456789;
let str2 = 2123456789.12;
console.log(str1.toLocaleString()); // 2,123,456,789
console.log(str2.toLocaleString()); // 2,123,456,789.12
複製代碼
// 處理字符串
let str1 = '2123456789';
let str2 = '2123456789.12';
// 利用正向預查 匹配 開頭一個數字\d 後面匹配這個數字後面必須是三個數字爲一組爲結尾或小數爲結尾
function thousandth(str) {
let reg = /\d(?=(?:\d{3})+(?:\.\d+|$))/g;
return str.replace(reg, '$&,');
}
console.log(thousandth(str1)); // 2,123,456,789
console.log(thousandth(str2)); // 2,123,456,789.12
複製代碼
var a = {
a: 1,
valueOf() {
return this.a++
}
}
if (a == 1 & a == 2 & a == 3) {
console.log(1)
}
複製代碼
let max = (a - b) + (a的索引- b的索引); 求a b
答案:
// 思路:其實也就是找出數組中當前的每一項與自身索引相加後的和的最大值以及與索引相加後的最小值的和 找出符合條件的兩項便可 如 let result = (maxItem-minItem) + (maxIndex-minIndex) 等價於 (maxItem+maxIndex) - (minItem+minIndex)
// let arr = [1, 2, 3, 4, 5, 6]; // 最簡單的測試數組 最小項1 最大項6
// 很顯然這個數組中最大值6與索引相加(6+5)是當中最大值11 1與索引相加(1+0)爲當中的最小值1(6 + 5)-(1+0)= 10
// 假設法
let arr = [2, 10, 9, 1, 8, 3, 4];
let minItem = arr[0]; // 假設第一項與自身索引的和是最小值 索引爲0所以省略
let maxItem = arr[0]; // 假設第一項與自身索引的和是最大值 索引爲0所以省略
let min = minItem; // 最小項
let max = maxItem; // 最大項
let minIndex = 0; // 最小項索引
let maxIndex = 0; // 最大項索引
for(let i = 1; i < arr.length; i++) {
let cur = arr[i] + i; // 當前項和自身索引的和
cur < minItem ? (minItem = cur, min = arr[i], minIndex = i) : null;
cur > maxItem ? (maxItem = cur, max = arr[i], maxIndex = i) : null;
}
console.log(maxItem, minItem); // 最大項與索引的和 最小項與索引的和
console.log(max, min); // 最大項 最小項
console.log(maxIndex, minIndex); // 最大項的索引 最小項的索引
複製代碼
// 如 balance('[()') = false; balance('[()()()]') = true
// 一
function match(a, b) {
return (a === '(' && b === ')') || (a === ')' && b === '(') || (a === '[' && b === ']') || (a === ']' && b === '[');
}
function balance(str) {
if (str.length % 2 === 0) {
let len = str.length;
for (let i = 0, j = len - 1; i < len / 2; i++, j--) {
if (!match(str[i], str[j])) {
return false;
}
}
return true;
}
return false;
}
console.log(balance('[()()()]')); // true
console.log(balance('[()')); // false
console.log(balance('[]()')); // false
// 二
function is_balance(str) {
return [...str].reduce((stack, c) => {
match(stack[stack.length - 1], c) ?
stack.pop() : stack.push(c);
return stack;
}, []).length === 0;
}
console.log(is_balance('[()()()]')); // true
console.log(is_balance('[()')); // false
console.log(is_balance('[]()')); // false
複製代碼
// 一
let arr1 = [-1, 3, 1, -5, 2]; // 如 [2, 4, -4, -3] => 4
function sum(arr) {
let prev = arr[0];
let sumArr = [];
let len = arr.length;
for(let i = 1; i < len; i++) {
let cur = arr[i];
sumArr.push(cur + prev);
prev = cur;
}
return Math.max(...sumArr);
}
console.log(sum(arr1));
// 二
function maxsum(arr) {
const M = [arr[0]];
let max = M[0];
for(let i = 1; i < arr.length; i++) {
M[i] = Math.max(arr[i], M[i - 1] + arr[i]);
max = Math.max(M[i], max);
}
return max;
}
複製代碼
// 正則表達式
let str = 'aabbccddeexxxxaa';
function uniq1(str) {
// return str.replace(/([a-z])(\1){1,}/g, '$1');
return str.replace(/(.)(?=\1)/g, '');
}
console.log(uniq1(str));
// 數組方式
function uniq2(str) {
let arr = str.split('');
let newArr = [arr[0]];
for(let i = 1; i < arr.length; i++) {
let cur = arr[i];
if (cur !== newArr[newArr.length - 1]) {
newArr.push(cur);
}
}
return newArr.join('');
}
console.log(uniq2(str));
複製代碼
百度網盤 密碼:ll8d
歡迎你們和我一塊兒來補充 上面不少也都是能夠優化的 我仍是一個成長中的小白,只是分享和記錄下本身碰到的問題 後續會持續更新...