重學一些JS基礎html
手機上看的話,由於掘金網頁/App端沒有導航欄~vue
而後我本身用 vuepress
作的文章備份,用 github Page
部署的,須要能夠看 這裏git
js 文件的話,能夠看 這裏github
function Animal(place) {
this.place = place;
this.type = 'animal';
this.run = function(m) {
console.log('run: ', m);
}
}
Animal.prototype = {
a: 'a'
}
複製代碼
function F(type) {
this.type = type;
this.f = 'f';
this.run = function(m) {
console.log('run: ', m);
}
}
F.prototype.a = 'a';
function _new() {
var obj = {};
var fn = Array.prototype.shift.call(arguments);
obj.__proto__ = fn.prototype;
var newObj = fn.apply(obj, arguments);
return (
Object.prototype.toString.call(newObj) === '[object Object]'
? newObj
: obj
);
}
// var f1 = new F();
var f1 = _new(F, 'F4');
console.log('f: ', f1); // { type: 'F4', f: 'f', run: [Function] }
console.log('a: ', f1.a); // a
console.log('type: ', f1.type); // F4
f1.run(2); // 2
複製代碼
function Cat1() {
this.c = 'c';
}
Cat1.prototype = new Animal();
console.log('-------- 1 ---------');
const cc1 = new Cat1();
console.log(cc1.type); // animal
console.log(cc1.a); // a
console.log(cc1.place); // undefined
cc1.run(2); // 2
複製代碼
繼承父類內置方法面試
function Cat2() {
// Animal.apply(this, arguments);
Animal.apply(this, ['深圳']);
// this.type = 'cat'; // 會覆蓋上面繼承的東西
this.c = 'c';
}
console.log('--------- 2 --------');
const cc2 = new Cat2();
console.log(cc2.type); // animal
console.log(cc2.a); // undefined
console.log(cc2.place); // 深圳
cc2.run(2); // 2
複製代碼
繼承父類的原型屬性算法
function Cat3() {
// Animal.apply(this, arguments);
Animal.apply(this, ['深圳']);
// this.type = 'cat'; // 會覆蓋上面繼承的東西
this.c = 'c';
}
Cat3.prototype = Object.create(Animal.prototype);
Cat3.prototype.constructor = Cat3;
console.log('--------- 3 --------');
const cc3 = new Cat3();
console.log(cc3.type); // animal
console.log(cc3.a); // a
console.log(cc3.place); // 深圳
cc3.run(2); // 2
複製代碼
function Cat4() {
// Animal.apply(this, arguments);
Animal.apply(this, ['深圳']);
// this.type = 'cat'; // 會覆蓋上面繼承的東西
this.c = 'c';
}
// 能夠改一下,Function.prototype.extend 寫方法
// 使用更方便:Child.extend(Parent);
function extend(Child, Parent) {
var fn = function() {};
fn.prototype = Parent.prototype;
Child.prototype = new fn();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
extend(Cat4, Animal);
console.log('--------- 4 --------');
const cc4 = new Cat4();
console.log(cc4.type); // animal
console.log(cc4.a); // a
console.log(cc4.place); // 深圳
cc4.run(2); // 2
複製代碼
瀏覽器是單線程,一旦遇到異步任務就會把其中的內容放到任務隊列 Task; 而後瀏覽器在執行同步任務的同時,不斷輪詢任務隊列,若是任務隊列中有任務,會按照 先進先出 的順序執行;數組
分爲微任務 Micro Task,宏任務 Macro Task;瀏覽器
宏任務隊列 中的宏任務 會在上一個宏任務執行完時執行;bash
微任務隊列 中的微任務 則是在主線程空閒時(如每個宏任務執行完)執行;期間有新的微任務會繼續執行,微任務都執行完纔會繼續輪詢 宏任務隊列;閉包
setTimeout
, setInterval
, requestAnimationFrame
, I/O
setTimeout
, setInterval
, setImmediate
Promsie.then
, Promsie.catch
, Promsie.finally
, MutationObserver
Promsie.then
, Promsie.catch
, Promsie.finally
, process.nextTick
console.log('Start!');
setTimeout(() => {
console.log('setTimeout1')
}, 0);
new Promise((resolve, reject) => {
console.log('Promise');
resolve();
setTimeout(() => {
console.log('setTimeout2');
}, 0);
Promise.resolve().then(() => {
console.log('then2');
})
}).then(() => {
console.log('then1');
})
console.log('End!');
// Start, Promise, End, then2, then1, setTimeout1, setTimeout2;
複製代碼
for 循環
調用 setTimeout
問題
由於 for 循環
是同步的,而 setTimeout
是異步宏任務,每一次循環都會在任務隊列添加一次 console.log(i)
,等到 i===9
的時候循環結束,這個時候 i++
因而 i=10
了,再依次調用 console.log(i)
,因此打印 10個10
// 10個10
for (var i=0; i<10; i++) {
setTimeout(() => {
console.log(i);
}, 0);
}
複製代碼
解決方法1: setTimeout
第三個參數
// 0-9
for (var i=0; i<10; i++) {
setTimeout((j) => {
console.log(j);
}, 0, i);
}
複製代碼
解決方法2: 閉包
// 0-9
for (var i=0; i<10; i++) {
(function(j) {
setTimeout(() => {
console.log(j);
}, 0)
})(i)
}
複製代碼
解決方法3: let
let
有塊級做用域
這樣是每次 for
都是獨立的 i
// 0-9
for (let i=0; i<10; i++) {
setTimeout((i) => {
console.log(i);
}, 0, i);
}
複製代碼
這樣就不行了,全部的 i
都是同一個 i
// 10個10
let i;
for (i=0; i<10; i++) {
setTimeout(() => {
console.log(i);
}, 0);
}
複製代碼
執行上下文,重在 執行 二字;
能夠理解爲是一個對象,通常函數是哪一個對象的 key
,這個函數的 this
就是那個對象;除非 call/bind/apply
改變了 this
/** * this */
function a() {
// 若是 a.call(obj),則是 { a: 'a', fn: [Function: fn] },
// 不然 global/Window
console.log('a: ', this);
b();
function b() {
console.log('b: ', this); // global/Window
c();
function c() {
console.log('c: ', this); // global/Window
}
}
}
const obj = {
a: 'a',
fn: function() {
console.log('fn: ', this); // { a: 'a', fn: [Function: fn] }
}
};
obj.fn();
a.call(obj);
複製代碼
看這位大佬的 文章
箭頭函數與普通函數的區別:
this
arguments
call/bind/apply
切換 thisnew
都是切換上下文,綁定 this
的
切換上下文,當即執行,參數展開非數組
/** * call * 切換上下文,當即執行,參數展開非數組 * @param {*} ctx 執行上下文 */
Function.prototype._call = function(ctx) {
ctx = ctx || {};
ctx.fn = this;
var args = [];
// 展開參數
// arguments[0] 是 ctx.fn 函數
for(var i=1; i<arguments.length; i++) {
args.push('arguments['+ i +']');
}
var res = eval('ctx.fn('+ args +')')
delete ctx.fn;
return res;
}
// 測試
var a = 'window-a';
var obj = {
a: 'obj-a',
fn: function(c, d) {
console.log('a:', this.a);
console.log('c:', c);
console.log('d:', d);
}
};
var obj2 = {
a: 'obj2-a'
};
var obj3 = {
a: 'obj3-a'
};
// a: obj2-a, c: cc2, d: dd2
obj.fn._call(obj2, 'cc2', 'dd2');
// a: obj3-a, c: cc3, d: dd3
obj.fn._call(obj3, 'cc3', 'dd3');
// a: window-a, c: cc-null, d: dd
obj.fn._call(null, 'cc-null', 'dd');
// a: window-a, c: cc-undefined, d: dd
obj.fn._call(undefined, 'cc-undefined', 'dd');
複製代碼
切換上下文,當即執行,參數是數組
/** * apply * 切換上下文,當即執行,參數爲數組 * @param {*} ctx 執行上下文 */
Function.prototype._apply = function(ctx) {
if (
arguments.length > 2 ||
Object.prototype.toString.call(arguments[1]) !== '[object Array]'
) {
console.warn('參數只能一個,且爲數組!');
return;
}
ctx = ctx || {};
ctx.fn = this;
var args = [];
for(var i=0; i<arguments[1].length; i++) {
args.push('arguments[1]['+ i +']');
}
var res = eval('ctx.fn('+ args +')');
delete ctx.fn;
return res;
}
// 測試
var a = 'window-a';
var obj = {
a: 'obj-a',
fn: function(c, d) {
console.log('a:', this.a);
console.log('c:', c);
console.log('d:', d);
}
};
var obj2 = {
a: 'obj2-a'
};
var obj3 = {
a: 'obj3-a'
};
// a: obj-a, c: cc, d: dd
obj.fn('cc', 'dd');
// a: obj2-a, c: cc2, d: dd2
obj.fn._apply(obj2, ['cc2', 'dd2']);
// a: obj3-a, c: cc3, d: dd3
obj.fn._apply(obj3, ['cc3', 'dd3']);
// a: window-a, c: cc-null, d: dd-null
obj.fn._apply(null, ['cc-null', 'dd-null']);
// a: window-a, c: cc-undefined, d: dd-undefined
obj.fn._apply(undefined, ['cc-undefined', 'dd-undefined']);
複製代碼
切換上下文,返回一個新函數;不會當即執行
/** * bind * 切換上下文,返回一個新函數;不會當即執行 * @param {*} ctx 執行上下文 */
Function.prototype._bind = function(ctx) {
ctx = ctx || {};
ctx.fn = this;
var args = [];
// 展開參數
// arguments[0] 是 ctx.fn 函數
for (var i=1; i<arguments.length; i++) {
args.push('arguments['+ i +']');
}
var res = eval('ctx.fn(' + args +')');
delete ctx.fn;
return function() {
res;
};
}
// 測試
var a = 'window-a';
var obj = {
a: 'obj-a',
fn: function(c, d) {
console.log('a:', this.a);
console.log('c:', c);
console.log('d:', d);
}
};
var obj2 = {
a: 'obj2-a'
};
var obj3 = {
a: 'obj3-a'
};
obj.fn('c', 'd'); // a: obj-a, c: c, d: d
var fn1 = obj.fn._bind(null, 'cc1', 'dd1');
fn1(); // a: window-a, c: cc1, dd1
var fn2 = obj.fn._bind(obj2, 'cc2', 'dd2');
fn2(); // a: obj2-a, c: cc2, d: dd2
var fn3 = obj.fn._bind(obj3, 'cc3', 'dd3');
fn3(); // a: obj3-a, c: cc3, d: dd3
// 這個時候是不能再綁定的,因此打印的是第一次綁定的內容
fn3.bind(obj2, 'cc2', 'dd2');
fn3(); // a: obj3-a, c: cc3, d: dd3
複製代碼
內部函數,私有變量
也能夠這麼理解:函數的內部函數引用外部的私有變量,那麼內部函數就是閉包;
複製代碼
只拷貝一層 key,若是這個 key 是複雜數據類型(Object/Array)的話,有引用賦值
function clone(objArr) {
var getType = o => Object.prototype.toString.call(o);
var isObjectOrArray = o => (
getType(o) === '[object Object]'
|| getType(o) === '[object Array]'
);
if (!isObjectOrArray(objArr)) return objArr;
var newObj = getType(objArr) === '[object Object]' ? {} : [];
Object.keys(objArr).forEach(item => {
newObj[item] = objArr[item];
})
return newObj;
}
var obj1 = {
a: 'a',
b: {
c: 'c1'
}
};
var obj2 = clone(obj1);
console.log(obj2); // { a: 'a', b: { c: 'c1' } }
obj2.a = 'a2';
obj2.b.c = 'c2';
console.log(obj2); // { a: 'a2', b: { c: 'c2' } }
console.log(obj1); // { a: 'a', b: { c: 'c2' } }
var arr1 = [1, [3]];
var arr2 = clone(arr1);
console.log(arr2); // [ 1, [ 3 ] ]
arr2[0] = 2;
arr2[1][0] = 4;
console.log(arr2); // [ 2, [ 4 ] ]
console.log(arr1); // [ 1, [ 4 ] ]
複製代碼
objArr
是否對象或數組,否的話直接返回;{}
,數組則 []
,key
,key
的值是對象或數組的話 遞歸執行/** * 深拷貝 * 判斷 `obj` 是否對象或數組,否的話直接返回; * 是的話,對象則給新變量初始化爲對象 `{}`,數組則 `[]`, * 而後 循環判斷每一個 `key`,`key` 的值是對象或數組的話 遞歸執行 */
function deepClone(objArr) {
var getType = o => Object.prototype.toString.call(o);
var isObjectOrArray = o => (
getType(o) === '[object Object]'
|| getType(o) === '[object Array]'
);
if (!isObjectOrArray(objArr)) return objArr;
var newObjArr = getType(objArr) === '[object Object]' ? {} : [];
Object.keys(objArr).forEach(item => {
newObjArr[item] = isObjectOrArray(objArr[item])
? deepClone(objArr[item])
: objArr[item]
})
return newObjArr;
}
var obj3 = {
a: 'a',
b: {
c: 'c1',
e: {
f: 'f'
}
},
d: [0, 1, [2]]
};
var obj4 = deepClone(obj3);
console.log(obj4); // { a: 'a', b: { c: 'c1', e: { f: 'f' } }, d: [ 0, 1, [ 2 ] ] }
obj4.a = 'a2';
obj4.b.c = 'c2';
obj4.b.e.f = 'f1';
obj4.d[0] = 1;
obj4.d[2][0] = 3;
console.log(obj4); // { a: 'a2', b: { c: 'c2', e: { f: 'f1' } }, d: [ 1, 1, [ 3 ] ] }
console.log(obj3); // { a: 'a', b: { c: 'c1', e: { f: 'f' } }, d: [ 0, 1, [ 2 ] ] }
複製代碼
item
、循環序列號
做爲兩個參數傳給回調函數item
,返回一個與原數組同樣長度的新數組語法:
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
複製代碼
實現:
/** * Array.prototype.map * 將 `item`、`循環序列號` 做爲兩個參數傳給回調函數 * 回調函數的返回值做爲 `item`,返回一個與原數組同樣長度的新數組 */
Array.prototype._map = function(cb) {
var arr = this;
var _this = arguments[1] || window;
var newArr = [];
// while 寫法
var i = 0;
while(i < arr.length) {
newArr.push(cb.call(_this, arr[i], i, arr));
i++;
}
// for 循環寫法:
// for(var i=0; i<arr.length; i++) {
// newArr.push(cb.call(_this, arr[i], i, arr));
// }
return newArr;
}
// 測試
var arr = [
{ a: 'a1', b: 'b1', c: ['c1'], d: 'd' },
{ a: 'a2', b: 'b1', c: ['c2'], d: 'd' },
{ a: 'a3', b: 'b2', c: ['c2'], d: 'd' },
{ a: 'a4', b: 'b3', c: ['c3'], d: 'd' },
];
var arr1 = arr._map(function(item) {
console.log('this: ', this); // { a: 'aaaa' }
return item.a
}, { a: 'aaaa' });
var arr2 = arr._map(item => item.b);
var arr3 = arr._map(item => {
return {
a: 'aa',
b: item.b
}
});
console.log(arr1); // [ 'a1', 'a2', 'a3', 'a4' ]
console.log(arr2); // [ 'b1', 'b1', 'b2', 'b3' ]
console.log(arr3);
複製代碼
for 循環,將 item
,循環序列號
,當前數組
做爲參數傳給回調函數;循環直接執行回調函數
語法:
arr.forEach(callback(currentValue [, index [, array]])[, thisArg]);
複製代碼
實現:
/** * Array.prototype.forEach * for 循環,將 `item`,`循環序列號`,`當前數組` 做爲參數傳給回調函數;循環直接執行回調函數 */
Array.prototype._forEach = function(cb) {
var arr = this;
var _this = arguments[1] || window;
var i = 0;
while(i < arr.length) {
cb.call(_this, arr[i], i, arr);
i++;
}
}
// 測試
var arr = [
{ a: 'a1', b: 'b1', c: ['c1'], d: 'd' },
{ a: 'a2', b: 'b1', c: ['c2'], d: 'd' },
{ a: 'a3', b: 'b2', c: ['c2'], d: 'd' },
{ a: 'a4', b: 'b3', c: ['c3'], d: 'd' },
];
arr.forEach(function(item) {
console.log('this: ', this); // this: { a: 'aaaa' }
item.a = 'aa';
item['d'] = 'dd';
}, { a: 'aaaa' });
console.log(arr);
/** [ { a: 'aa', b: 'b1', c: [ 'c1' ], d: 'dd' }, { a: 'aa', b: 'b1', c: [ 'c2' ], d: 'dd' }, { a: 'aa', b: 'b2', c: [ 'c2' ], d: 'dd' }, { a: 'aa', b: 'b3', c: [ 'c3' ], d: 'dd' } ] */
複製代碼
item
,循環序列號
,當前數組
做爲參數傳給回調函數;item
組成的數組語法:
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
複製代碼
實現:
/** * Array.prototype.filter * 將 `item`,`循環序列號`,`當前數組` 做爲參數傳給回調函數; * 回調函數的返回值做爲條件,去過濾原數組,返回符合條件的 `item` 組成的數組 */
Array.prototype._filter = function(cb) {
var arr = this;
var _this = arguments[1] || window;
var newArr = [];
var i = 0;
while(i < arr.length) {
var res = Boolean(cb.call(_this, arr[i], i));
if (res) newArr.push(arr[i]);
i++;
}
return newArr;
}
var arr1 = arr._filter(function(item) {
console.log('this: ', this); // { a: 'aaaa' }
return item.a === 'a1'
}, { a: 'aaaa' });
var arr2 = arr._filter(item => item);
console.log(arr1); // [ { a: 'a1', b: 'b1', c: [ 'c1' ], d: 'd' } ]
console.log(arr2);
/** [ { a: 'a1', b: 'b1', c: [ 'c1' ], d: 'd' }, { a: 'a2', b: 'b1', c: [ 'c2' ], d: 'd' } ] */
複製代碼
item
,循環序列號
,當前數組
做爲參數傳給回調函數;item
語法:
var item = arr.find(callback(element[, index[, array]])[, thisArg])
複製代碼
實現:
/** * Array.prototype.find * 將 `item`,`循環序列號`,`當前數組` 做爲參數傳給回調函數; * 回調函數的返回值做爲條件,只找一個,返回第一個符合條件的 `item` */
Array.prototype._find = function(cb) {
var arr = this;
var _this = arguments[1] || window;
var item = null;
var i = 0;
while(i < arr.length && item === null) {
if (Boolean(cb.call(_this, arr[i], i))) {
item = arr[i];
}
i++;
}
return item;
}
// 測試
var arr = [
{ a: 'a1', b: 'b1', c: ['c1'], d: 'd' },
{ a: 'a2', b: 'b1', c: ['c2'], d: 'd' },
{ a: 'a3', b: 'b2', c: ['c2'], d: 'd' },
{ a: 'a4', b: 'b3', c: ['c3'], d: 'd' },
];
var item1 = arr._find(item => item);
var item2 = arr._find(function(item) {
console.log('this: ', this); // { a: 'aaaa' }
return item.b === 'b1'
}, { a: 'aaaa' });
var item3 = arr._find(item => item.b === 'b2');
console.log(item1); // { a: 'a1', b: 'b1', c: [ 'c1' ], d: 'd' }
console.log(item2); // { a: 'a1', b: 'b1', c: [ 'c1' ], d: 'd' }
console.log(item3); // { a: 'a3', b: 'b2', c: [ 'c2' ], d: 'd' }
複製代碼
item
,循環序列號
,當前數組
做爲參數傳給回調函數;item
符合;也能夠反向用 Array.some
找一個不符合的來替代語法:
var isTrue = arr.every(callback(element[, index[, array]])[, thisArg])
複製代碼
實現:
/** * Array.prototype.every * 將 `item`,`循環序列號`,`當前數組` 做爲參數傳給回調函數; * 回調函數的返回值做爲條件,判斷是否全部 `item` 符合;也能夠反向用 `Array.some` 找一個不符合的來替代 */
Array.prototype._every = function(cb) {
var arr = this;
var _this = arguments[1] || window;
var result = false;
var i = 0;
while(i < arr.length) {
result = Boolean(cb.call(_this, arr[i], i));
i++;
}
return result;
}
var res1 = arr._every(function(item) {
console.log('this: ', this); // { a: 'aaaa' }
return item.d === 'd'
}, { a: 'aaaa' });
var res2 = arr._every(item => item.a === 'a');
console.log(res1); // true
console.log(res2); // false
複製代碼
item
,循環序列號
,當前數組
做爲參數傳給回調函數;item
,只找一個,返回 Boolean
語法:
var hasItem = arr.some(callback(element[, index[, array]])[, thisArg])
複製代碼
實現:
/** * Array.prototype.some * 將 `item`,`循環序列號`,`當前數組` 做爲參數傳給回調函數; * 查找符合條件的 `item`,只找一個,返回 `Boolean` */
Array.prototype._some = function(cb) {
var arr = this;
var _this = arguments[1] || window;
var result = false;
var i = 0;
while(i < arr.length && !result) {
result = Boolean(cb.call(_this, arr[i], i));
i++;
}
return result;
}
var has_a1 = arr._some(function(item) {
console.log('this: ', this); // { a: 'aaaa' }
return item.a === 'a1'
}, { a: 'aaaa' });
console.log(has_a1); // true
var has_b = arr._some(item => item.b === 'b');
console.log(has_b); // false
var has_b1 = arr._some(item => item.b === 'b1');
console.log(has_b1); // true
複製代碼
item
,循環序列號
,當前數組
做爲參數傳給回調函數;語法:
var result = arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
複製代碼
實現:
/** * Array.prototype.reduce * 將 `item`,`循環序列號`,`當前數組` 做爲參數傳給回調函數; * 累計循環;兩個參數,第一個爲函數(其中,第一個形參爲第二個參數),第二個參數可不傳; * 回調函數的返回值做爲下次回調的第二個參數,最終返回回調函數的返回值 */
Array.prototype._reduce = function() {
var arr = this;
var i = 0;
var cb = arguments[0]; // 第一個參數,回調函數
var cur = arguments[1] || null; // 第二個參數
while(i < arr.length) {
cur = cb(cur, arr[i], i, arr);
i++;
}
return cur;
}
// 求和
var list = [1,2,3,4,5,6,7,8,9];
var result = list._reduce((acc, cur) => acc + cur, 0);
console.log(result); // 45
// 統計某個字符出現的次數
var list2 = ['aa', 'bb', 'jj', 'cc', 'dd', 'aa', 'b1'];
var result2 = list2._reduce((acc, cur) => {
acc[cur] ? acc[cur]++ : acc[cur] = 1;
return acc;
}, {});
console.log(result2); // { aa: 2, bb: 1, jj: 1, cc: 1, dd: 1 }
複製代碼
這個是在又一次面試的時候,面試官問的,挺簡單,雖然第一次遇到這麼問的
/** * 私有屬性,公有屬性 */
function fn() {
// private
var list = [];
// public
this.a = function() {
console.log('a');
}
// public
this.b = function() {
console.log('b');
}
}
const f = new fn();
console.log(f.list); // undefined
f.a(); // a
複製代碼
item
去重;item[key]
去重;/** * 數組去重 * 簡單數組按照 `item` 去重; * 複雜數組按照 `item[key]` 去重; * @param {*} arr * @param {*} key 去重的 key,可選 */
function uniarr(arr, key) {
var getType = o => Object.prototype.toString.call(o);
if (getType(arr) !== '[object Array]') return arr;
if (key && !arr[0].hasOwnProperty(key)) {
console.warn(arr, '[item] 不存在key: '+key);
return [];
}
var newArr = [];
arr.forEach(item => {
var arrItem = key
? item.hasOwnProperty(key) ? item[key] : item
: item;
var hasItem = newArr.some(newitem => {
return (key ? newitem[key] === arrItem : newitem === arrItem)
});
if(!hasItem) newArr.push(item);
})
return newArr;
}
var list1 = [1,2,3,4,5,6,1,2,3];
console.log(uniarr(list1)); // [ 1, 2, 3, 4, 5, 6 ]
var list2 = [{id: 1}, {id: 2}, {id: 3}, {id: 2}];
console.log(uniarr(list2, 'id'));
//[ { id: 1 }, { id: 2 }, { id: 3 } ]
console.log(uniarr(list2, 'id1'));
// [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 2 } ] '[item] 不存在 key: id1'
// []
複製代碼
item
是否數組,否的話直接 push 到新數組,/** * 數組扁平化 * 判斷 `item` 是否數組,否的話直接 push 到新數組, * 是的話遞歸 * @param {*} arr */
function singlearr(arr) {
var getType = o => Object.prototype.toString.call(o);
if (getType(arr) !== '[object Array]') return arr;
var newArr = [];
arr.forEach(item => {
getType(item) === '[object Array]'
? newArr = newArr.concat(singlearr(item))
: newArr.push(item)
})
return newArr;
}
var list2 = [1,2,[3,4],[5,[6,7]]];
console.log(singlearr(list2));
複製代碼
正則去先後空格最簡單
/** * 字符串先後去空格 */
String.prototype._trim = function() {
var str = this;
return str.replace(/^\s|\s$/g,'');
}
var str = ' st r ';
console.log(str.split('')); // [ ' ', 's', 't', ' ', 'r', ' ' ]
console.log(str._trim().split('')); // [ 's', 't', ' ', 'r' ]
複製代碼
url
轉化的 key/value
對象,key
且 url
轉化的對象有這個 key
的時候,直接返回值/** * 獲取 URL 參數 * 默認返回 url 轉化的 key/value 對象, * 有傳 key 且 url 轉化的對象有這個 key 的時候,直接返回值 * @param {*} url 形如 a=1&b=2 * @param {*} key */
function urlUtil(url, key) {
if (typeof url !== 'string') return;
if (!url.includes('=')) return url;
var obj = {};
url.split('&').forEach(item => {
const [key, value] = item.split('=');
obj[key] = value;
})
if (key && obj.hasOwnProperty(key)) {
return obj[key];
}
if (key && !obj.hasOwnProperty(key)) {
console.warn(`url: ${url} 中不存在 ${key} 字段`);
return;
}
return obj;
}
var url = 1;
console.log(urlUtil(url)); // a
var url1 = 'a=1';
console.log(urlUtil(url1)); // { a: '1' }
console.log(urlUtil(url1, 'a')); // 1
console.log(urlUtil(url1, 'b')); // url: a=1 中不存在 b 字段 undefined
var url2 = 'a=1&b=2';
console.log(urlUtil(url2)); // { a: '1', b: '2' }
console.log(urlUtil(url2, 'a')); // 1
console.log(urlUtil(url2, 'b')); // 2
複製代碼
經常使用的如 數字千分號(3位)反向,銀行卡號(4位),身份證號(4位)等
/** * 數字千分號 * @param {*} num */
function numThousand(num) {
if (typeof (num-0) !== 'number') return num;
if (num.length < 4) return num;
// 正則
// var newNum = (num+'').replace(
// /(\d)(?=(?:\d{3})+$)/g,
// '$1,'
// );
// 函數
var newNum = (num+'').split('');
var arr = [];
do {
// 從後面開始分割
var start = newNum.length > 3 ? newNum.length - 3 : 0;
arr.push(newNum.splice(start, newNum.length).join(''));
} while(newNum.length > 0)
newNum = arr.reverse().join(',');
delete arr;
return newNum;
}
var num1 = 1234567;
console.log(numThousand(num1)); // 1,234,567
var num2 = 123;
console.log(numThousand(num2)); // 123
var num3 = '123';
console.log(numThousand(num3)); // 123
var num4 = '12345';
console.log(numThousand(num4)); // 12,345
var card = '62564749929292';
// 62,564,749,929,292
console.log(numThousand(card));
複製代碼
/** * 字符按長度分割 * @param {*} num 數字 * @param {*} len 分割的長度,默認三位 * @param {*} sep 分隔符 默認 ',' */
function stringSeparate(str, {len = 3, sep = ','} = {}) {
if (typeof (str+'') !== 'string') return str;
if (str.length < 4) return str;
var newStr = (str+'').split('');
var arr = []
do {
arr.push(newStr.splice(0, len).join(''));
} while(newStr.length > 0)
newStr = arr.join(sep);
delete arr;
return newStr;
}
var num1 = 1234567;
console.log(stringSeparate(num1)); // 123,456,7
var num2 = 123;
console.log(stringSeparate(num2)); // 123
var num3 = '123';
console.log(stringSeparate(num3)); // 123
var num4 = '12345';
console.log(stringSeparate(num4)); // 123,45
var card = '6217123456789012345';
// 6217 1234 5678 9012 345
console.log(stringSeparate(card, {len: 4, sep: ' '}));
複製代碼
暫時就搞兩個~
一個一個對比,互換位置
/** * 冒泡排序 * @param {*} arr */
function BubbleSort(arr){
const getType = o => Object.prototype.toString.call(o);
if (getType(arr) !== '[object Array]') return arr;
for (var i=0; i<arr.length; i++) {
for (var j=i+1; j<arr.length; j++) {
var temp = '';
if (arr[i] > arr[j]) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
var arr = [1,3,4,12,34,5,22,8];
console.log(arr.sort()); // [ 1, 3, 4, 5, 8, 12, 22, 34 ]
console.log(BubbleSort(arr)); // [ 1, 3, 4, 5, 8, 12, 22, 34 ]
複製代碼
left: []
,一份小於參考值 right: []
left/right
, 返回一個 left+mid+right
組成的數組/** * 快速排序 * 取一個參考值,而後將剩下的分爲兩份,一份大於參考值的 `left: []`,一份小於參考值 `right: []` * 而後分別遞歸 `left/right`, 返回一個 `left+mid+right` 組成的數組 * @param {*} arr 排序的數組 * @param {*} key 一級 key */
function FastSort(arr, key) {
const getType = o => Object.prototype.toString.call(o);
if (getType(arr) !== '[object Array]') return arr;
if (arr.length <= 1) return arr;
if (key && !arr[0].hasOwnProperty(key)) {
console.warn(arr, '[item] 不存在key: '+key);
return [];
}
if (!key && getType(arr[0]) === '[object Object]') {
console.warn('傳一個 key 做爲排序字段');
return [];
}
var mid = arr.shift();
var left = [];
var right = [];
arr.forEach(item => {
var arrItem = key
? item.hasOwnProperty(key) ? item[key] : item
: item;
var midItem = key
? item.hasOwnProperty(key) ? mid[key] : mid
: mid;
arrItem <= midItem ? left.push(item) : right.push(item);
});
return FastSort(left, key).concat(mid).concat(FastSort(right, key));
}
var arr = [1,3,4,12,34,654,89,1,66,12,23,45,10,230,342,980];
// [ 1, 1, 3, 4, 10, 12, 12, 23, 34, 45, 66, 89, 230, 342, 654, 980 ]
console.log(FastSort(arr));
var arr1 = [{num: 10}, {num: 26}, {num: 8}, {num: 36}];
// 傳一個 key 做爲排序字段, []
console.log(FastSort(arr1));
// [ { num: 8 }, { num: 10 }, { num: 26 }, { num: 36 } ]
console.log(FastSort(arr1, 'num'));
複製代碼
能夠看 這裏
理解概念以後仍是很好寫的
/** * 求斐波那契數列 * n<=2時爲1,從3開始,每一個數等於前兩個之和 * @param {*} n */
function fb2(n) {
const arr = [];
for (var i = 0; i <= n; i++) {
arr.push(
i <= 2 ? 1 : arr[i - 1] + arr[i - 2]
)
}
return arr;
}
console.log(fb2(15));
// [ 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610 ]
複製代碼
思路:
/**
* 動態規劃
* 1塊,4塊,5塊,求總數N塊的最小硬筆數
* 思路:一、先求最大數的倍數 二、其中兩個的組合(大數優先) 三、三個的組合
*/
function getCoinNum(N) {
let n1 = 1;
let n2 = 4;
let n3 = 5;
// 輸出結果組合、最少數量,如:12: { result: '5*2,4*0,2*1', minCount: 4 }
const getResult = (result, minCount) => ({ result, minCount });
if (N < n2) return getResult(`${n1}*${N}`, N / n1);
if (N === n1) return getResult(`${n1}*1`, 1);
if (N === n2) return getResult(`${n2}*1`, 1);
if (N%n3 === 0) return getResult(`${n3}*${N/n3}`, N/n3);
for (var j = 0; j < N/n2; j++) {
for (var k = 0; k < N/n3; k++) {
if (N === n3 * k + n2 * j) return getResult(`${n3}*${k},${n2}*${j}`, j + k);
if (N === n2 * j) return getResult(`${n2}*${j}`, j);
// N - n3*k - n2*j) 結果小於 4,則剩下的由 1 組成
if ((N - n3 * k - n2 * j) > 0 && (N - n3 * k - n2 * j) < n2) {
return getResult(
`${n3}*${k},${n2}*${j},${(N - n3 * k - n2 * j)}*1`,
j + k + (N - n3 * k - n2 * j)
);
}
}
}
}
// for (var i=0; i<=50; i++) console.log(`${i}: `, getCoinNum(i));
/**
* 打印:
* 0: { result: '1*0', minCount: 0 }
1: { result: '1*1', minCount: 1 }
2: { result: '1*2', minCount: 2 }
3: { result: '1*3', minCount: 3 }
4: { result: '4*1', minCount: 1 }
5: { result: '5*1', minCount: 1 }
6: { result: '5*1,4*0,1*1', minCount: 2 }
7: { result: '5*1,4*0,2*1', minCount: 3 }
8: { result: '5*1,4*0,3*1', minCount: 4 }
9: { result: '5*1,4*1', minCount: 2 }
10: { result: '5*2', minCount: 2 }
11: { result: '5*2,4*0,1*1', minCount: 3 }
12: { result: '5*2,4*0,2*1', minCount: 4 }
13: { result: '5*2,4*0,3*1', minCount: 5 }
14: { result: '5*2,4*1', minCount: 3 }
15: { result: '5*3', minCount: 3 }
16: { result: '5*3,4*0,1*1', minCount: 4 }
17: { result: '5*3,4*0,2*1', minCount: 5 }
18: { result: '5*3,4*0,3*1', minCount: 6 }
19: { result: '5*3,4*1', minCount: 4 }
20: { result: '5*4', minCount: 4 }
21: { result: '5*4,4*0,1*1', minCount: 5 }
22: { result: '5*4,4*0,2*1', minCount: 6 }
23: { result: '5*4,4*0,3*1', minCount: 7 }
24: { result: '5*4,4*1', minCount: 5 }
25: { result: '5*5', minCount: 5 }
26: { result: '5*5,4*0,1*1', minCount: 6 }
27: { result: '5*5,4*0,2*1', minCount: 7 }
28: { result: '5*5,4*0,3*1', minCount: 8 }
29: { result: '5*5,4*1', minCount: 6 }
30: { result: '5*6', minCount: 6 }
31: { result: '5*6,4*0,1*1', minCount: 7 }
32: { result: '5*6,4*0,2*1', minCount: 8 }
33: { result: '5*6,4*0,3*1', minCount: 9 }
34: { result: '5*6,4*1', minCount: 7 }
35: { result: '5*7', minCount: 7 }
36: { result: '5*7,4*0,1*1', minCount: 8 }
37: { result: '5*7,4*0,2*1', minCount: 9 }
38: { result: '5*7,4*0,3*1', minCount: 10 }
39: { result: '5*7,4*1', minCount: 8 }
40: { result: '5*8', minCount: 8 }
41: { result: '5*8,4*0,1*1', minCount: 9 }
42: { result: '5*8,4*0,2*1', minCount: 10 }
43: { result: '5*8,4*0,3*1', minCount: 11 }
44: { result: '5*8,4*1', minCount: 9 }
45: { result: '5*9', minCount: 9 }
46: { result: '5*9,4*0,1*1', minCount: 10 }
47: { result: '5*9,4*0,2*1', minCount: 11 }
48: { result: '5*9,4*0,3*1', minCount: 12 }
49: { result: '5*9,4*1', minCount: 10 }
50: { result: '5*10', minCount: 10 }
*/
複製代碼