首頁>技術>

前端基礎瀏覽器瀏覽器的快取機制:強快取與協商快取,以及其區別是什麼?儲存相關:localstorage、sessionStorage、cookie等分別是做什麼用的,區別是什麼?瀏覽器的network面板裡面的東西,主要是timing下面的時間段代表的都是什麼意思?TTFB是什麼?瀏覽器的performance用過嗎,是用來幹什麼的?跨域的原理,跨域的實現方式有哪幾種?瀏覽器環境下的event loop是怎樣的?其實也就是宏任務和微任務,可以看下這篇文章JavaScript基礎資料型別和引用資料型別基礎資料型別:Undefined、Null、Boolean、String、Number、Symbol引用資料型別:Object、Array、Date、RegExp、Function此處可能會考察,typeof、instanceof;包括手動實現以下typeof和instanceof

// 實現typeoffunction type(obj) {	return Object.prototype.toString.call(a).slice(8,-1).toLowerCase();}
// 實現instanceoffunction instance(left,right){    left=left.__proto__    right=right.prototype    while(true){       if(left==null)       	  return false;       if(left===right)          return true;       left=left.__proto__    }}
原型鏈

理解原型鏈是做什麼的,也就是:例項.proto === 建構函式.prototype

Object.prototype.__proto__ === null // trueFunction.prototype.__proto__ === Object.prototype // trueObject.__proto__ === Function.prototype // true

有個比較好的問題,可以思考下:

function F() {}Object.prototype.b = 2;F.prototype.a = 1;var f = new F();console.log(f.a) // 1console.log(f.b) // 2console.log(F.a) // undefinedconsole.log(F.b) // 2

上面程式碼,為什麼F.a是undefined?

function F() {}Object.prototype.b = 2;Function.prototype.a = 1;var f = new F();console.log(f.a) // undefinedconsole.log(f.b) // 2console.log(F.a) // 1console.log(F.b) // 2

上面程式碼,為什麼f.a是undefined?

function F() {}F.prototype.a = 1;var f1 = new F()F.prototype = {    a: 2}var f2 = new F()console.log(f1.a) // 1console.log(f2.a) // 2
繼承

繼承的幾種方式:

原型鏈繼承:
function SuperType() {  this.name = 'Yvette';  this.colors = ['red', 'blue', 'green'];}SuperType.prototype.getName = function () {    return this.name;}function SubType() {    this.age = 18;}SubType.prototype = new SuperType();SubType.prototype.constructor = SubType;  let instance1 = new SubType();instance1.colors.push('yellow');console.log(instance1.getName());console.log(instance1.colors); // ['red', 'blue', 'green', 'yellow']let instance2 = new SubType();console.log(instance2.colors); // ['red', 'blue', 'green', 'yellow']
缺點:透過原型來實現繼承時,原型會變成另一個型別的例項,原先的例項屬性變成了現在的原型屬性,該原型的引用型別屬性會被所有的例項共享。(引用型別值被所有例項共享)在建立子型別的例項時,沒有辦法在不影響所有物件例項的情況下給超型別的建構函式中傳遞引數建構函式繼承:
function SuperType(name) {    this.name = name;    this.colors = ['red', 'blue', 'green'];}function SubType(name) {    SuperType.call(this, name);}let instance1 = new SubType('draven');instance1.colors.push('yellow');console.log(instance1.colors);  // ['red', 'blue', 'green', 'yellow']let instance2 = new SubType('ben');console.log(instance2.colors);  // ['red', 'blue', 'green']
優點:可以向超類傳遞引數解決了原型中包含引用型別值被所有例項共享的問題 缺點:方法都在建構函式中定義,函式複用無從談起。超型別原型中定義的方法對於子型別而言都是不可見的。組合繼承:
function SuperType(name) {    this.name = name;    this.colors = ['red', 'blue', 'green'];}SuperType.prototype.sayName = function () {    console.log(this.name);}function SuberType(name, age) {    SuperType.call(this, name);    this.age = age;}SuberType.prototype = new SuperType()SuberType.prototype.constructor = SuberTypelet instance1 = new SuberType('draven', 25);instance1.colors.push('yellow');console.log(instance1.colors); // ['red', 'blue', 'green', 'yellow']instance1.sayName(); //dravenlet instance2 = new SuberType('ben', 22);console.log(instance2.colors);  // ['red', 'blue', 'green']instance2.sayName();//ben
缺點:無論什麼情況下,都會呼叫兩次超型別建構函式:一次是在建立子型別原型的時候,另一次是在子型別建構函式內部。 優點:可以向超類傳遞引數每個例項都有自己的屬性實現了函式複用寄生組合式繼承,寄生組合繼承是引用型別最理性的繼承正規化,使用Object.create在組合繼承的基礎上進行最佳化:
function SuperType(name) {    this.name = name;    this.colors = ['red', 'blue', 'green'];}SuperType.prototype.sayName = function () {    console.log(this.name);}function SuberType(name, age) {    SuperType.call(this, name);    this.age = age;}SuberType.prototype = Object.create(SuperType.prototype)SuberType.prototype.constructor = SuberTypelet instance1 = new SuberType('draven', 25);instance1.colors.push('yellow');console.log(instance1.colors); //[ 'red', 'blue', 'green', 'yellow' ]instance1.sayName(); //dravenlet instance2 = new SuberType('ben', 22);console.log(instance2.colors); //[ 'red', 'blue', 'green' ]instance2.sayName();//ben
ES6繼承:
class SuperType {    constructor(age) {        this.age = age;    }    getAge() {        console.log(this.age);    }}class SubType extends SuperType {    constructor(age, name) {        super(age); // 呼叫父類的constructor(age)        this.name = name;    }}let instance = new SubType(18, 'draven');instance.getAge(); // 18
類的內部所有定義的方法,都是不可列舉的。(ES5原型上的方法預設是可列舉的)閉包:柯理化:
// 實現固定引數的curryfunction add(a, b, c, d) {    return a + b + c + d}function curry(fn) {    const length = fn.length    let params = []    return function func() {        params = params.concat([].slice.call(arguments))        if (params.length === length) {            const res = fn.apply(null, params);            params = [];            return res;        } else {            return func;        }    }}const addCurry = curry(add);console.log(addCurry(1, 2)(3, 4)); // 10console.log(addCurry(2)(3)(4)(5)); // 14
// 實現隨意引數的柯理化function add() {    let params = [].slice.call(arguments);    function func() {        params = params.concat([].slice.call(arguments))        return func;    }    func.toString = () => {        return  params.reduce((a, b) => {            return a + b;        }, 0);    }    return func;}console.log(add(1, 2)(3, 4)); // 10console.log(add(2)(3)(4)(5)); // 14
防抖和節流:

函式防抖和節流,都是控制事件觸發頻率的方法。

// 防抖export function debounce(func, wait, immediate) {    let timeout, args, context, timestamp, result;    let nowTime = Date.now || function () {        return new Date().getTime();    };    const later = function () {        let last = nowTime() - timestamp;        if (last < wait && last >= 0) {            timeout = setTimeout(later, wait - last);        } else {            timeout = null;            if (!immediate) {                result = func.apply(context, args);                if (!timeout) context = args = null;            }        }    };    return function () {        context = this;        args = arguments;        timestamp = nowTime();        let callNow = immediate && !timeout;        if (!timeout) timeout = setTimeout(later, wait);        if (callNow) {            result = func.apply(context, args);            context = args = null;        }        return result;    };};
// 節流function throttle(fn, threshhold) {    let timeout    let start = new Date;    threshhold = threshhold || 160    return function () {        const context = this, args = arguments, curr = new Date() - 0        clearTimeout(timeout)//總是幹掉事件回撥        if (curr - start >= threshhold) {            fn.apply(context, args)            start = curr        } else {            //讓方法在脫離事件後也能執行一次            timeout = setTimeout(function(){                fn.apply(context, args)            }, threshhold);        }    }}
var/let/const

這部分主要考查對let和var的理解,變數提升等。

看下面這個程式碼的執行結果是什麼?

var foo = {n: 1};var bar = foo;foo.x = foo = {n: 2};bar = ?foo = ?

上面的執行結果是:bar = {n:1,x:{n:2}}; foo={n:2};

a();var a=3;function a(){alert(10)}alert(a)a=6;a()

上面的執行結果是:10 3 error;最後的error是因為a不是個function;

== 與 ===

隱式轉換的步驟: 主要搞明白在強等和雙等的時候做了什麼事情,也就好理解了。

強等(===)會首先比較兩邊的型別是否相同,如果不同則直接返回false;如果型別相同的話,則是按照==來判斷的,我們來看下==所引起的隱式轉換。

雙等號引起的隱式轉換

一、首先看雙等號前後有沒有NaN,如果存在NaN,一律返回false。

二、再看雙等號前後有沒有布林,有布林就將布林轉換為數字。(false是0,true是1)

三、接著看雙等號前後有沒有字串, 有三種情況:

1、對方是物件,物件使用toString()或者valueOf()進行轉換;2、對方是數字,字串轉數字;(前面已經舉例)3、對方是字串,直接比較;4、其他返回false

四、如果是數字,對方是物件,物件取valueOf()或者toString()進行比較, 其他一律返回false

五、null, undefined不會進行型別轉換, 但它們倆相等

.toString()方法和.valueOf()方法數值轉換

通常情況下我們認為,將一個物件轉換為字串要呼叫toString()方法,轉換為數字要呼叫valueOf()方法,但是真正應用的時候並沒有這麼簡單,看如下程式碼例項:

let obj = { name: "draven", age: 28}console.log(obj.toString()); //[object Object]

同理,我們再看valueOf()方法:

let arr = [1, 2, 3];console.log(arr.valueOf());//[1, 2, 3]

從上面的程式碼可以看出,valueOf()方法並沒有將物件轉換為能夠反映此物件的一個數字。相反,我們用toString()

let arr = [1, 2, 3];console.log(arr.toString());//1,2,3

注:很多朋友認為,轉換為字串首先要呼叫toString()方法, 其實這是錯誤的認識,我們應該這麼理解,呼叫toString()方法可以轉換為字串,但不一定轉換字串就是首先呼叫toString()方法。

我們看下下面程式碼:

let arr = {};arr.valueOf = function () { return 1; }arr.toString = function () { return 2; }console.log(arr == 1);//truelet arr = {};arr.valueOf = function () { return []; }arr.toString = function () { return 1; }console.log(arr == 1);//true

上面程式碼我們可以看出,轉換首先呼叫的是valueOf(),假如valueOf()不是數值,那就會呼叫toString進行轉換!

let arr = {};arr.valueOf = function () { return "1"; }arr.toString = function () { return "2"; }console.log(arr == "1");//true

假如"1"是字串,那麼它首先呼叫的還是valueOf()。

let arr = [2];console.log(arr + "1");//21

上面的例子,呼叫的是toString();因為arr.toString()之後是2。

轉換過程是這樣的,首先arr會首先呼叫valueOf()方法,但是數字的此方法是簡單繼承而來,並沒有重寫(當然這個重寫不是我們實現),返回值是陣列物件本身,並不是一個值型別,所以就轉而呼叫toString()方法,於是就實現了轉換為字串的目的。

說明

大多數物件隱式轉換為值型別都是首先嚐試呼叫valueOf()方法。但是Date物件是個例外,此物件的valueOf()和toString()方法都經過精心重寫,預設是呼叫toString()方法,比如使用+運算子,如果在其他算數運算環境中,則會轉而呼叫valueOf()方法。

let date = new Date();console.log(date + "1"); //Sun Apr 17 2014 17:54:48 GMT+0800 (CST)1console.log(date + 1);//Sun Apr 17 2014 17:54:48 GMT+0800 (CST)1console.log(date - 1);//1460886888556console.log(date * 1);//1460886888557

舉例鞏固提高 下面我們一起來做做下面的題目吧!

let a;console.dir(0 == false);//trueconsole.dir(1 == true);//trueconsole.dir(2 == {valueOf: function(){return 2}});//trueconsole.dir(a == NaN);//falseconsole.dir(NaN == NaN);//falseconsole.dir(8 == undefined);//falseconsole.dir(1 == undefined);//falseconsole.dir(2 == {toString: function(){return 2}});//trueconsole.dir(undefined == null);//trueconsole.dir(null == 1);//falseconsole.dir({ toString:function(){ return 1 } , valueOf:function(){ return [] }} == 1);//trueconsole.dir(1=="1");//trueconsole.dir(1==="1");//false[] == 0 // true

上面的都可以理解了嗎?最後一行程式碼結果是true的原因是什麼?

es6

這部分考查對es6的掌握熟練度,新增的一些型別,語法,等等。推薦大家看一看阮一峰老師的es6的文章

手寫實現js實現bind
// 實現bindFunction.prototype.myBind = function (context,...args) {    let self = this;    let params = args;    return function (...newArgs) {        self.call(context, ...params.concat(...newArgs))    }}var a = {    name: 'this is a'}function sayName() {    console.log(this.name, arguments)}let newfn = sayName.myBind(a, '1234', '5678')newfn('1000', '2000')
js實現call
// 實現callFunction.prototype.myCall = function (context,...args) {    context.fn = this;    context.fn(...args)    delete context.fn;}var a = {    name: 'this is a'}function sayName() {    console.log(this.name, arguments)}sayName.myCall(a, '1234', '5678')
js實現setInterval
// setTimeout 實現setIntervalfunction mySetInterval(fn, time) {    let timer = {};    function timeout() {        timer.t = setTimeout(() => {            fn();            timeout()        }, time)    }    timeout();    return timer;}function clearMyInterval(timer) {    clearTimeout(timer.t)}
promise

promise考察點比較多,包括實現自己的promise和一些呼叫的知識點

推薦兩篇文章:實現Promise和Promise題

css盒模型,盒模型的margin、padding有什麼特點?flex佈局的屬性都有什麼,都代表什麼含義?左右居中佈局、上下居中佈局、上下左右居中佈局,實現方式是什麼?單行超出省略...,多行超出省略...自適應佈局響應式佈局less、scss、stylusrem、em、vw等移動端1px如何實現?css如何實現三角形?css的link和import區別是什麼?htmlmeta用來幹嘛的塊元素、行元素區別和舉例html5新增的標籤有哪些?video標籤的使用,事件等前端框架vuevue基本

一、 vue的生命週期: beforeCreate、created、beforeMounte、mounted、beforeUpdate、updated、beforeDestory、destroyed;

二、 Vue元件通訊:

props(emit);$attr和$listeners,事件bus物件(bus.$on, bus.$emit),provide(inject),v-model(props:value, emit:input ),$children,vuex

三、keep-alive使用及原理,LRU演算法

四、vue的v-show和v-if的區別;vue的watch和computed的區別;

五、其他:vue的服務端渲染,例如框架nuxt的使用;前端元件庫的使用,如element-ui;

vue2與vue3

3是Proxy+Reflect,2是Object.defineProperty;dom-diff的最佳化;componentApi等

vue-router實現的模式:hash & history;兩者的區別和分析事件:全域性:beforeEach、afterEach;路由:beforeEnter;元件內:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave實現原理,原始碼vuexvuex是什麼?vuex官網state、getters、mutations(commit)、actions(dispatch)、modulemapState、mapMutations、mapGetters、mapActions;subscribe,subscribeAction實現原理,原始碼等react

一、生命週期

  1.react16之前的生命週期是什麼?  2.react16之後的生命週期是什麼?  3.react16和react16之前的版本有什麼區別?  4.requestAnimationFrame是什麼?requestIdleCallback是什麼?如何實現requestAnimationFrame
// 實現requestAnimationFramevar lastTime = 0window.requestAnimationFrame = function (callback) {    let now = Date().now;    let timeCall = Math.max(0, 16 - (lastTime - now));    let id = setTimeout(function () {        callback(now + timeCall)    }, timeCall)        lastTime = now + timeCall;    return id;}

二、react-hooks

1.常用的reacthooks都有哪些?2.使用useEffect模擬componentDidMount和componentDidUpdate3.useEffect返回的是什麼?做什麼用的?4.useEffect和useLayoutEffect的區別是什麼?5、useMemo和useCallback是什麼?做什麼用的?有什麼區別?

三、react-router

1.如何實現路由切換,有幾種方式?2.有哪幾個鉤子函式?onEnter和routerWillLeave3.link與a標籤的區別什麼?

四、redux

1.redux是什麼?做什麼的?與vuex有什麼區別?2.redux包含哪幾塊?state,reducers,actions

五、其他:

1.服務端渲染next;2.元件庫antd;3.PureComponent與Component的區別是什麼?4.react的效能最佳化有什麼建議?5.封裝一個promise的setState
// 使用promise封裝setStatefunction setStateP(state) {    return new Promise(resolve => {        this.setState(state, resolve)    })}
工具型-webpack1.webpack是什麼?2.webpack的工作原理是什麼?3.寫過plugin嗎?怎麼實現的?4.loader是做什麼的?loader和plugin的區別什麼?5.關於webpack的最佳化建議等nodeJsevent-loop:可以看下這篇文章nodejs的event loopegg:宣告週期,目錄結構,常用外掛koa:Koa的中介軟體與express的中介軟體的區別,實現一個洋蔥圈模型的函式
// 洋蔥圈模型function compose(middleware) {    return function (context, next) {        let index = -1;        function dispatch(i) {            if (i <= index) {                return Promise.reject('err')            }            index = i;            let fn = middleware[i];            if(i === middleware.length) {                fn = next;            }            if (!fn) {                return Promise.resolve();            }            try {                return Promise.resolve(fn(context, function next() {                    return dispatch(i + 1);                }))            } catch (e) {                return Promise.reject(e);            }        }        dispatch(0);    }}
child_processspawn、exec、execFile、fork、fork與spawn類似,不同在於fork建立子程序需要執行js檔案;spawn與exec和execFile不同的是,後兩者建立時可以指定timeout屬性設定超時時間,一旦程序超時就會被殺死;exec與execFile不同的是,exec執行的是已有命令,execFile執行的是檔案。pm2pm2常用命令:start、stop、delete、logs、restart、list-i 引數,啟動多執行緒;watch,-w,監聽檔案改變pm2配置檔案,可以配置多個app,apps陣列,啟動 pm2 start pm2.connfig.js —only=one-app-name計算機基礎http系列三次握手是什麼?為什麼需要三次?四次揮手是什麼?為何需要四次?http1、http2、https的區別是什麼?https是如何進行加密的?請求如何取消?AbortController排序氣泡排序
// 從小到大排序:function bubblingSort(list){     let temp;     for(let i=0; i<list.length; i++){          for(let j=i; j<list.length; j++){               if(list[i] > list[j]){                    temp = list[i];                    list[i] = list[j];                    list[j] = temp;               }          }     }     return list;}let res = bubblingSort([10, 8, 2, 23, 30, 4, 7, 1])console.log(res); // [1, 2, 4, 7, 8, 10, 23, 30]
直接選擇排序
從小到大排序:function selectSort(list){     let r,temp;     for(let j=0; j<list.length; j++){          for(let i = j+1; i<list.length; i++){               if(list[j] > list[i]){                   temp = list[j];                   list[j] = list[i];                   list[i] = temp;               }          }     }     return list;}let res = selectSort([10, 8, 2, 23, 30, 4, 7, 1])console.log(res); // [1, 2, 4, 7, 8, 10, 23, 30]
直接插入排序

整個排序過程為n-1趟插入,即先將序列中第1個記錄看成是一個有序子序列,然後從第2個記錄開始,逐個進行插入,直至整個序列有序。

function insertSort(list) {    let flag;    for(let index = 1; index < list.length; index++) {        flag = list[index];        let j = index - 1;        while (flag < list[j]) {            list[j + 1] = list[j]            j--;        }        list[j + 1] = flag;    }     return list;}let res = insertSort([10, 8, 2, 23, 30, 4, 7, 1])console.log(res); // [1, 2, 4, 7, 8, 10, 23, 30]
希爾排序

排序過程:先取一個正整數d1<n,把所有相隔d1的記錄放一組,組內進行直接插入排序;然後取d2<d1,重複上述分組和排序操作;直至di=1,即所有記錄放進一個組中排序為止

function shellSort(list) {    const length = list.length;    let j, temp;    for (let d = parseInt(length / 2); d >= 1; d = parseInt(d / 2)) {        for (let i = d; i < length; i++) {            temp = list[i];            j = i - d;            while (j >= 0 && temp < list[j]) {                list[j + d] = list[j];                j -= d;            }            list[j + d] = temp;        }    }    return list;}let res = shellSort([10, 8, 2, 23, 30, 4, 7, 1])console.log(res); // [1, 2, 4, 7, 8, 10, 23, 30]
快速排序

透過一次排序,將待排序記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小,則可對這兩部分記錄進行排序,以達到整個序列有序。

function quickSort(v,left,right){    if(left < right){        var key = v[left];        var low = left;        var high = right;        while(low < high){            while(low < high && v[high] > key){                high--;            }            v[low] = v[high];            while(low < high && v[low] < key){                low++;            }            v[high] = v[low];        }        v[low] = key;        quickSort(v,left,low-1);        quickSort(v,low+1,right);    }}let list = [10, 8, 2, 23, 30, 4, 7, 1]quickSort(list, 0, 7)console.log(list); // [1, 2, 4, 7, 8, 10, 23, 30]
其他tcp/ip協議的五層模型:應用層、傳輸層、網路層、資料鏈路層、物理層演算法相關,leetcode上面刷吧二叉樹等的遍歷,前中後序遍歷,深度優先,廣度優先;棧、佇列的使用連結串列的使用其他hybird
1、什麼是hybrid?2、jsbridge是什麼?如何實現?3、hybrid開發需要注意什麼?
預載入和懶載入:
1.包括圖片影片等內容的懶載入(IntersectionObserver的使用封裝)2.資料的預載入,純h5的prefetch && 與端結合的預載入方案3.js的按需載入(配合webpack的import().then()的split實現)
dom文件的載入步驟是什麼?
1、 解析HTML結構。2、 載入外部指令碼和樣式表文件。3、 解析並執行指令碼程式碼。4、 構造HTML DOM模型。//ready5、 載入圖片等外部檔案。6、 頁面載入完畢。//load
從瀏覽器輸入url,到展現完成,經過了什麼?
此問題網上有很多回答,屬於自由發揮問題;回答的深度和廣度能夠看出本人的知識面。此處就不多說了。
前端效能最佳化等方方面面總結

沒怎麼有答案,只是把自己梳理的相關的內容整理總結了下,如果有不會的,還是得自己查一下。

最後祝大家年前年後,換工作的話可以找到心儀的工作,

13
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 工作三年!全靠大佬的Java筆記,年底跳槽阿里漲了10K