前端日常開發(fā)必背知識點

寫在前面:

今年從春招到秋招面試了國內(nèi)所謂的BAT、TMD等互聯(lián)網(wǎng)企業(yè)前端開發(fā)。各大公司的面試風(fēng)格可謂各有千秋,從編程基礎(chǔ)、框架原理到算法、網(wǎng)絡(luò)再到對新技術(shù)(比如PWA)的認(rèn)知地考核,其中尤其以前端基礎(chǔ)JS編程為考核重點,各大公司對此地看重程度已經(jīng)到了一言不合就"丟算法擼代碼"的地步。而小編在筆試機(jī)試這樣的編碼過程中居然一時忘掉了部分基本操作,結(jié)果不言而喻,就好比打野忘了帶懲戒,出門忘了買裝備,閃現(xiàn)送人頭啊。痛定思痛,下定決心將這些基本操作好好整理一番日常背記,也當(dāng)是做一個前端技能的分享和討論了,希望廣大前端愛好者能夠在評論區(qū)查漏補(bǔ)缺。(結(jié)尾有驚喜喲)


1.基本類型和引用類型

基本類型:Number, String, Null, Undefined, Boolean, Symbol(ES6數(shù)據(jù)類型)

引用類型:Object、Array、RegExp、Date、Function、單體內(nèi)置對象(Global、Math)

區(qū)別:基本類型,操作和保存在變量的實際的值(保存在棧區(qū));引用類型,值指向內(nèi)存空間的引用,就是地址,所指向的內(nèi)存中保存著變量所表示的一個值或一組值,所以操作的是對象的引用(引用存放在棧區(qū),實際對象保存在堆區(qū))。

1.1 類型檢測

使用 typeof進(jìn)行基本類型檢測,使用instanceof檢測對象還是數(shù)組

類型 結(jié)果
Undefined "undefined"
Null "object"
Boolean "boolean"
Number "number"
String "string"
Symbol(ECMAScript 6 新增) "symbol"
函數(shù)對象 "function"
任何其他對象 "object"
檢測數(shù)組和對象:(Array其實是Object 的子類)
var a = [];
console.log(a instanceof Array); // true
console.log(a instanceof Object); // true

var a = {};
console.log(a instanceof Array); // false
console.log(a instanceof Object); // true

1.2 String操作

String <=> Number:

字符串轉(zhuǎn)數(shù)字:
parseInt(str, 進(jìn)制) // 默認(rèn)十進(jìn)制, 轉(zhuǎn)化為整數(shù),小數(shù)點后默認(rèn)不保留
parseFloat(str) // 轉(zhuǎn)化為浮點數(shù)
+str // 屌屌的轉(zhuǎn)化方法, 但字符串包含非數(shù)字會報錯

數(shù)字轉(zhuǎn)字符串:
let str1 = num.toString();
let str2 = String(num);
let str3 = num +  '';

String <=> Array:

字符串轉(zhuǎn)數(shù)組
let arr = str.split(',') // 一般是空格或者逗號

數(shù)組轉(zhuǎn)字符串
let str = arr.join('');

模板字符串

`Hello, ${變量}`

1.3 常用正則

去逗號
let newStr = str.replace(/,/g,'');
去空格(一般輸入框輸入都要做這個)
let newStr = str.replace(/(^\s*)|(\s*$)/g, ''); // 去除左右空格
let newStr = str.replace(/\s+/g,"");  // 去除所有空格
用戶名
let userPattern = /^[a-zA-Z0-9_-]{4,16}$/; // 4到16位(字母,數(shù)字,下劃線,減號)
userPattern.test(str);
電話號碼
let mPattern = /^1[34578]\d{9}$/;
附:密碼/身份證號/E-mail/URL就不上了,太長了背了沒意義,用的時候查就好了

1.4 Array操作

在阿里騰訊頭條的筆試機(jī)試中,對數(shù)組的操作可以說是前端算法的核心,數(shù)組操作的基本方法全是必背的重中之重。

1.4.1 Array.from()
  1. 偽數(shù)組對象和可迭代對象[見附錄]轉(zhuǎn)化為數(shù)組:

     let arr = Array.from(str/new Set()/new map());
    
  2. 轉(zhuǎn)化數(shù)組后對每項進(jìn)行操作

     let arr = Array.from('123', item => parseInt(item) + 1); // 2, 3, 4
    
  3. 去重(可以說這是最精彩的地方了)

     Array.from(new Set(arr));
    
1.4.2 拷貝數(shù)組

使用以下方法能復(fù)制數(shù)組保存在堆內(nèi)存中的值,但不能深拷貝數(shù)組(數(shù)組中的數(shù)組或者對象依舊只是復(fù)制了引用沒有復(fù)制到其在堆內(nèi)存中的值)。[數(shù)組和對象的深淺拷貝以及for循環(huán)遞歸實現(xiàn)方式本文不涉及]

let arr2 = [...arr1];
let arr2 = arr1.slice();
let arr2 = arr1.concat([]); // 此方法不常用

深拷貝(對象也是如此)

let arr2 = JSON.parse(JSON.stringify(arr1));
1.4.3 找出最大最小值
Math.max.apply(null, arr);
Math.min.apply(null, arr);
// ES6的寫法
Math.max(...arr);
1.4.4 數(shù)組排序
  1. sort()

     1.數(shù)組排序
     function compare(a, b) { return a-b; }
     arr.sort(compare);
     2.數(shù)組對象排序(開發(fā)中常用)
     function compare(property) {
         return (obj1, obj2) => {
             return obj1[property] - obj2[property];
         }
     }
     let students = [{name: "xx", age: 20}, {name: "hh", age: 19}];
     students.sort(compare('age'));
    
  2. 快排

1.4.5 其他方法
push(item) // 末尾添加
pop() // 刪除末尾
shift() // 刪除開頭
unshift() // 開頭添加
sort() // 排序
reverse() // 反轉(zhuǎn)
slice(start, end) // 截斷拷貝, 接收起始和結(jié)束位置兩參數(shù)并返回相應(yīng)的數(shù)組,不影響原數(shù)組
splice(index, num) // 切片,取出從index位置開始的num個值,原數(shù)組被截取
splice(index, 0, sth) // 插入sth
splice(index, 1, sth) // 替換為sth
▲  forEach(item, index, array) // 對每一項執(zhí)行某些操作
▲  filter(item, index, array) // 返回滿足條件(true)的項組成的數(shù)組
▲  map(item, index, array) // 返回對每一項執(zhí)行某些操作組成的數(shù)組
every(item, index, array) // 如果該函數(shù)對每一項都返回true,則返回true
some(item, index, array) // 如果該函數(shù)對某一項返回true,則返回true
reduce() // 從頭到尾逐個遍歷,迭代數(shù)組中的所有項
includes(sth, index); // 檢測數(shù)組中是否含有sth,index代表開始查找的位置,返回布爾值

另:二分查找

1.4.5 對象數(shù)組根據(jù)對象某key值去重(日常工作常用)
let arr = [{showId: 'C', age: '11'}, {showId: 'A', age: '11' },
{ showId: 'B', age: '11'}, { showId: 'B', age: '11'},
{ showId: 'B', age: '12'},{ showId: 'B', age: '13'}];

// 根據(jù)showId去重到新數(shù)組newArr
const newArr = [];
arr.forEach(item => {
  // 過濾,如果有重復(fù)項就添加到過濾數(shù)組,那么長度就不為0就不會推入新數(shù)組。
  // 如果沒有重復(fù)項長度就為0就推入新數(shù)組。
  newArr.filter(m => m.showId === item.showId).length === 0 && 
  newArr.push(item);
});

1.5 Object操作

1.5.1 創(chuàng)建

創(chuàng)建方式:工廠模式、構(gòu)造函數(shù)模式、原型模式、動態(tài)原型模式、寄生構(gòu)造函數(shù)模式、穩(wěn)妥構(gòu)造函數(shù)模式。

工廠模式
function createObj(key) {
    const obj = new Object();
    obj.key = key;
    obj.sayKey = function(){ 方法 };
    return obj;
}
// 使用:const xuqingfeng = createObj('xuqingfeng');

構(gòu)造函數(shù)(對象屬性最好用構(gòu)造函數(shù)) + 原型(對象方法最好用原型),這樣的話每個實例都會有自己的一份實例屬性的副本,同時又共享著對方法的引用,最大限度地節(jié)省了內(nèi)存:

// 構(gòu)造函數(shù)模式用于定義實例屬性
function Person(name) {
    this.name = name;
}
// 原型模式用于定義方法和共享的屬性
Person.prototype = {
    /* 默認(rèn)情況下,所有原型對象都會自動獲得一個constructor屬性,
    這個屬性是一個指向prototype屬性所在函數(shù)的指針,
    這里的Person.prototype.constructor指向Person */
    constructor : Person, 
    sayName : function() { 方法 }
}
ES6的簡寫(簡直不要太好用, 三大框架很多寫法基于此):
屬性簡寫:
let keyVal = 'xuqingfeng';
const obj = {keyVal}; // obj: { keyVal: 'xuqingfeng' }
方法簡寫:
const obj = {
    method() {}
};
獲取對象屬性:
 const { keyVal } = obj; // React的const { data } = this.props; 就是這么個原理,前提是對象中也有對應(yīng)屬性(key)
1.5.2 繼承

繼承方式:原型鏈、借用構(gòu)造函數(shù)、組合繼承、原型式繼承、寄生式繼承、寄生組合式繼承。

組合繼承

這種方式既通過在原型上定義方法實現(xiàn)了函數(shù)復(fù)用,又能夠保證每個實例都有它自己的屬性。

function A_Obj(name) {
    this.name = name;
}
A_Obj.prototype.sayName = function() { A_Obj的方法 };
function B_Obj(name, age) {
    A_Obj.call(this, name); // 繼承屬性
    this.age = age;
}
B_Obj.prototype = new A_Obj(); // 繼承A_Obj的所有方法
B_Obj.prototype.constructor = B_Obj; // 改變指向非常關(guān)鍵
B_Obj.prototype.sayAge = function() { B_Obj的方法 };

object.create()實現(xiàn)對象繼承 - 特別地提及下這個方法,它可以直接使用創(chuàng)建一個新對象

// 實現(xiàn)繼承 - 方法
let extend = (Child, Parent) => {
    Child.prototype = Object.create(Parent.prototype); // 拷貝Parent原型對象
    Child.prototype.constructor = Child; // 將Child構(gòu)造函數(shù)賦值給Child的原型對象
}
// 實例
const Par = function () { this.name = 'xuqingfeng'; }
Par.prototype.getName = function () { return this.name; }
// 繼承
const Cld = function () { Par.call(this); }
extend(Cld, Par);
// 使用
let testChild = new Cld();
console.log(testChild.getName())
1.5.3 拷貝

淺拷貝:

const copyObj = Object.assign({}, obj);
const Obj2 = {...Obj1};

淺拷貝并修改key的value或添加key與value: const Obj2 = {...Obj1, ['key']: 'newOrCover'},示例如下

const firObj = { a: '1', s: { ss: 'sss' } };
const secObj = { ...firObj, ['b']: '2' }
secObj.a = '777';
firObj.a = '666';
secObj.s.ss = 'secObj-s';
firObj.s.ss = 'firObj-s';
console.log(firObj, secObj);  // { a: '666', s: { ss: 'firObj-s' } } { a: '777', s: { ss: 'firObj-s' }, b: '2' }

并集-合并兩個對象/數(shù)組,后者覆蓋前者(深度覆蓋),最終形成并集: const Obj3 = Object.assign({}, Obj1, Obj2);,示例如下

const firObj = { a: '1', b: 'b', s: { ss: 'fir-s' } };
const secObj = { a: '2', c: 'c', s: { ss: 'sec-s' } }
const newObj = Object.assign({}, firObj, secObj);
console.log(newObj); // { a: '2', b: 'b', s: { ss: 'sec-s' }, c: 'c' }
const firArr = [1, 2, 3, 'a', 'b'];
const secArr = [1, 3, 5, 7];
const newArr = Object.assign([], firArr, secArr);
console.log(newArr); // [ 1, 3, 5, 7, 'b' ]

深拷貝[ for循環(huán)遞歸深拷貝見上面數(shù)組,Object.assign合并對象和深拷貝移步MDN ]:

let obj2 = JSON.parse(JSON.stringify(obj1)); 
1.5.4 其他方法
Object.freeze() // 凍結(jié)對象:其他代碼不能刪除或更改任何屬性。
Object.keys() // 返回一個包含所有給定對象自身可枚舉屬性名稱的數(shù)組。
Object.values() // 返回給定對象自身可枚舉值的數(shù)組。
Object.entries() // 返回給定對象自身可枚舉屬性的[key, value]數(shù)組
Object.defineProperty() // vue數(shù)據(jù)雙向綁定的核心方法,建議上 MDN 一觀

1.6 Function操作

1.6.1 參數(shù)轉(zhuǎn)化為數(shù)組(不知參數(shù)個數(shù))

數(shù)組原型slice方法

function fc() {
    Array.prototype.slice.call(arguments) ; // 這個方法可以將只要具有l(wèi)ength屬性的對象轉(zhuǎn)成數(shù)組
}

▲ rest 參數(shù)

function fc(...arr) { console.log(arr); }

參數(shù)cancat為數(shù)組

function fc() { return [].concat.apply([], arguments); }
1.6.2 檢測函數(shù)參數(shù)是否含有某個值(sth)
[].includes.call(arguments, sth)
1.6.3 函數(shù)設(shè)置可改的默認(rèn)參數(shù)
function func1(a, b='123123',c={id: 1}){
    console.log(a,b,c)
}
func1('徐清風(fēng)','xuqingfeng', 44) // 徐清風(fēng), xuqingfeng, 44

1.7 MathDate

Math方法:

Math.ceil() // 執(zhí)行向上舍入
Math.floor() // 執(zhí)行向下舍入
Math.round() // 執(zhí)行標(biāo)準(zhǔn)舍入
▲ Math.random() // 返回大于等于0小于1的隨機(jī)數(shù)

獲取當(dāng)前時間:

let now = new Date();
console.log(now.toLocaleString()); // 2018-8-23 17:48:47
console.log([now.getFullYear(), now.getMonth()+1, now.getDate()].join('-')); // 2018-8-23

2.JS編程基本操作

2.1 三元運(yùn)算 - 用起來超刺激

公式:條件1 ? 真結(jié)果1 : ( 條件1.1 ? 真結(jié)果1.1 : (條件1.1.1 ? 真結(jié)果1.1.1:假結(jié)果1.1.1)), 一個常用示例:

node.style.display = (node.style.display === "block" ? "none" :  "block");

2.2 在做JS判斷時的 truefalse (if判斷、與非判斷、三元運(yùn)算判斷等)

值為falsefalsenullundefined''(空字符串,空格不代表空)0NaN
值為truetrue對象字符串(包括空格)任意非0數(shù)值(包括Infinity)

2.3 與或非運(yùn)算

&& :如果第一個值為 true,則 && 后面的值將顯示在輸出中,否則值為第一個值。

let a = false && 123; // false
let b = ' ' && 123; // 123, 注意這里是空格不是空

|| :如果第一個值為 false,則 || 后面的值將顯示在輸出中,否則值為第一個值。

let a = false || 123; // 123
let b = ' ' || 123; // ' '

附錄:

  1. 偽數(shù)組對象和可迭代對象:
  • 偽數(shù)組對象(擁有一個 length 屬性和若干索引屬性的任意對象)
  • 可迭代對象(可以獲取對象中的元素,如 MapSet 等)
  1. 福利-今年春秋招阿里騰訊頭條機(jī)試(遠(yuǎn)程視頻直接擼代碼)題:

     1. 正則電話號碼
     2. 兩個超過JS數(shù)值范圍的數(shù)字相加
     3. 一片英文文章重復(fù)出現(xiàn)次數(shù)最多的單詞及其出現(xiàn)次數(shù)
     4. 創(chuàng)建一個 Person 類,其包含公有屬性 name 和私有屬性 age 以及公有方法 setAge;
        創(chuàng)建一個 Teacher 類,使其繼承 Person ,并包含私有屬性 studentCount 和私有方法 setStudentCount
     5. 兼容的事件監(jiān)聽方法
     6. 快排
     7. 拖拽一個方塊隨機(jī)移動
     8. 事件觀察者
     9. promise按序執(zhí)行三個函數(shù)
     10. 封裝一個flat方法,將多維數(shù)組扁平化為一維數(shù)組
     11. 實現(xiàn)一個簡易的JQ選擇器功能(要求能夠獲取標(biāo)簽、類、Id)
     12. 實現(xiàn)簡易的虛擬DOM(意味著用對象構(gòu)造DOM),然后生成DOM結(jié)構(gòu),
         只要求屬性值(比如class、id等屬性能夠正常獲取和調(diào)用),
         不要求節(jié)點增刪查改(這涉及到diff算法)。
     13. 對象數(shù)組根據(jù)某個屬性去重【這個上面有提到】
    

以上知識點是個人日常開發(fā)常用的,關(guān)于編程思想、算法邏輯這些大知識點這里就不一一列出了,畢竟吃透這些東西不是光靠背下來就能解決的,更多的是積累、理解和自己的思考,這些東西是程序員一輩子都學(xué)不完的,所以列出毫無意義。
因為寫這些小知識點也只是一時興起,肯定有很多遺漏,文首就有提及過寫這些內(nèi)容的目的就是分享和討論,所以歡迎大家在評論區(qū)進(jìn)行補(bǔ)充,如果有必要的話可以在github上開一個issue。


2018-11-21 更新:新增數(shù)組、對象淺拷貝方法,新增獲取對象key方法,新增對象數(shù)組去重方法,面試新題


2019-2-27 更新:新增常用的對象拷貝方法和合并方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。