手寫代碼-Javascript篇

1 Javascript 基礎(chǔ)

1.1 手寫Object.create

解析:Object.create() 方法創(chuàng)建一個(gè)新對象门怪,使用現(xiàn)有的對象來提供新創(chuàng)建的對象的proto

解決方案:將傳入對象作為原型票髓。

function create(obj) {
    const A = function() {};
    A.prototype = obj;
    return new A();
}

1.2 手寫instanceof

解析:instanceof 運(yùn)算符 用于檢測構(gòu)造函數(shù)的 prototype 屬性是否出現(xiàn)在某個(gè)實(shí)例對象的原型鏈上攀涵。

解決方案:

  1. 獲取類型的原型
  2. 獲取對象的原型
  3. 然后遞歸循環(huán)對象的原型是否為類型原型,直到null(原型鏈終端)炬称,如果不同,則為false涡拘,相同為true
function NewInstanceOf(source, target) {
    if (typeof source !== 'object') {
        return false;
    }
    // 這里也可以使用while循環(huán)方式
    if (source.__proto__ !== target.prototype) {
        if (source.__proto__ === null) {
            return false;
        }
        return NewInstanceOf(source.__proto__, target);
    }
    return true;
}

1.3 手寫new操作符號

解析:new 運(yùn)算符 創(chuàng)建一個(gè)用戶定義的對象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對象的實(shí)例玲躯。

new會(huì)經(jīng)過以下的過程:

  1. 首先會(huì)創(chuàng)建一個(gè)新的對象
  2. 設(shè)置對象原型為函數(shù)的prototype原型
  3. 設(shè)置函數(shù)this指向這個(gè)對象,執(zhí)行構(gòu)造函數(shù)代碼(設(shè)置函數(shù)函數(shù)屬性為對象屬性)
  4. 判斷當(dāng)前返回類型鳄乏,如果是值類型跷车,則返回創(chuàng)建對象,如果是引用類型橱野,就返回這個(gè)引用類型對象朽缴。
const newFunc = (obj, ...args) => {
    let newObj = null;
    if (typeof obj !== 'function') {
        throw ('type error');
    }
    newObj = Object.create(obj.prototype);
    const result = obj.apply(newObj, args);
    if (result && (typeof result === 'function' || typeof result === 'function')) {
        return result;
    }
    return newObj;
}

1.4 手寫防抖函數(shù)

解析:指在事件被觸發(fā) n 秒后再執(zhí)行回調(diào),如果在這 n 秒內(nèi)事件又被觸發(fā)水援,則重新計(jì)時(shí)密强。

這可以使用在一些點(diǎn)擊請求的事件上茅郎,避免因?yàn)橛脩舻亩啻吸c(diǎn)擊向后端發(fā)送多次請求。

function debounce(fn, time) {
    let timer = null;
    return function (...args) {
        !!timer && window.clearTimeout(timer);
        timer = setTimeout(() => fn(...args), time);
    }
}

1.5 手寫節(jié)流函數(shù)

解析:規(guī)定一個(gè)單位時(shí)間或渤,在這個(gè)單位時(shí)間內(nèi)系冗,只能有一次觸發(fā)事件的回調(diào)函數(shù)執(zhí)行,如果在同一個(gè)單位時(shí)間內(nèi)某事件被觸發(fā)多次薪鹦,只有一次能生效掌敬。

節(jié)流可以使用在 scroll 函數(shù)的事件監(jiān)聽上,通過事件節(jié)流來降低事件調(diào)用的頻率池磁。

function throttle(fn, time) {
    let timer = null;
    return function (...args) {
        if (timer) {
            return;
        }
        timer = setTimeout(() => {
            window.clearTimeout(timer);
            timer = null;
            fn(...args);
        }, time);
    }
}

1.6 手寫判斷類型函數(shù)

解決方案:主要是根據(jù)為typeof為object做區(qū)分奔害,使用Object.prototype.toString獲對象類型信息。

function computedType(arg) {
    if (null === arg) {
        return 'null';
    }
    if (typeof arg === 'object') {
        const str = Object.prototype.toString.call(arg);
        return str.replace(/\]/, '').split(' ')[1];
    }
    return typeof arg;
}

1.7 手寫call函數(shù)

解決方案:

  1. 判斷調(diào)用對象是否為函數(shù)地熄,即使我們是定義在函數(shù)原型上面华临,但是可能出現(xiàn)call等調(diào)用方式
  2. 判斷上下文傳入對象是否存在,否則离斩,返回window
  3. 需要將函數(shù)作為上下文對象的屬性银舱,使用上下文對象調(diào)用這個(gè)方法,保存結(jié)果返回
  4. 刪除剛才上下文函數(shù)的新增屬性跛梗,返回結(jié)果
Function.prototype.newCall = function(context = window, ...args) {
    if (typeof this !== 'function') {
        throw('type error');
    }
    context._fn = this;
    const result = context._fn(...args);
    delete context._fn;
    return result;
}

1.8 手寫apply函數(shù)

解決反感:實(shí)現(xiàn)和call類似寻馏,只是參數(shù)需要簡單處理下。

Function.prototype.newApply = function(context = window, args) {
    if (typeof this !== 'function') {
        throw('type error');
    }
    context._fn = this;
    const result = context._fn(...args);
    delete context._fn;
    return result;
}

1.9 手寫bind函數(shù)

解析:bind需要返回一個(gè)函數(shù)核偿。其參數(shù)除了上下文執(zhí)行對象诚欠,還有函數(shù)執(zhí)行上下文的參數(shù)。

Function.prototype.newBind = function(context = window, ...args) {
    if (typeof this !== 'function') {
        throw('type error');
    }
    context.fn = this;
    return function (...newArgs) {
        const result = context.fn(...args, ...newArgs);
        delete context.fn;
        return result;
    }
}

1.10 函數(shù)柯里化

解析:只傳遞給函數(shù)一部分參數(shù)來調(diào)用它漾岳,讓它返回一個(gè)函數(shù)去處理剩下的參數(shù)轰绵。

function curry(fn, ...args) {
    // 這里重點(diǎn)在于:
    // 1.使用fn.length來獲取函數(shù)參數(shù)長度
    // 2.當(dāng)少于長度的時(shí)候,返回閉包函數(shù)形式尼荆,這個(gè)函數(shù)可以累積參數(shù)長度
    return args.length === fn.length
        ? fn(...args)
        : (...newArgs) => curry(fn, ...args, ...newArgs);
}

2 數(shù)據(jù)轉(zhuǎn)換

2.1 交換a b值左腔,不能使用臨時(shí)變量

解決方案:利用兩數(shù)相減,兩數(shù)相加捅儒,計(jì)算差值液样。

a = a + b;
b = a - b;
a = a - b;

另外還能利用js高級語法來進(jìn)行交換。

[a, b] = [b, a];

2.2 實(shí)現(xiàn)數(shù)據(jù)亂序輸出

解決方案:從0開始遍歷巧还,產(chǎn)生一個(gè)隨機(jī)數(shù)鞭莽,隨機(jī)數(shù)不為小于當(dāng)前數(shù),將隨機(jī)數(shù)和當(dāng)前值進(jìn)行交換麸祷,直至數(shù)組末端澎怒。

function renderRandomArray(arr = []) {
    for(let i = 0; i < arr.length; i++) {
        const random = i + Math.round(Math.random() * (arr.length - i - 1));
        [arr[i], arr[random]] = [arr[random], arr[i]];
    }
    return arr;
}

2.3 數(shù)組扁平化

解決方案:遞歸

function flatten(arr) {
    let result = [];
    for(let i = 0; i < arr.length; i++) {
      if(Array.isArray(arr[i])) {
        result = result.concat(flatten(arr[i]));
      } else {
        result.push(arr[i]);
      }
    }
    return result;
}

2.4 數(shù)據(jù)去重

解決方式:map

function uniqueArray(arr) {
    let map = {};
    let newArr = [];
    for (const i of arr) {
        if (!map[i]) {
            map[i] = true;
            newArr.push(i);
        }
    }
    return newArr;
}

2.5 將js對象轉(zhuǎn)化為樹結(jié)果

// 轉(zhuǎn)換前:
source = [
    { id: 1, parentId: 0, name: 'rank1' },
    { id: 2, parentId: 1, name: 'rank2' },
    { id: 3, parentId: 2, name: 'rank3' }
]

// 轉(zhuǎn)換為:
tree = [{ 
    id: 1, 
    parentId: 0, 
    name: 'rank1',
    children: [{
        id: 2,
        parentId: 1,
        name: 'rank2',
        children: [{ id: 3, parentId: 1, name: 'rank3' }]
    }]
}]

解決方案:

  1. 建立一個(gè)map,將數(shù)組每一項(xiàng)的id作為key阶牍,項(xiàng)值作為value喷面。
  2. 設(shè)置臨時(shí)變量result星瘾,遍歷數(shù)組,判斷是否有父節(jié)點(diǎn)乖酬,如果有死相,將父節(jié)點(diǎn)取出,設(shè)置父節(jié)點(diǎn)的children為該項(xiàng)咬像,如果沒有算撮,push到result中县昂。
  3. 最后返回result肮柜。
function JsonToTree(arr) {
    if (!Array.isArray(arr)) {
        return arr;
    }
    let result = [];
    let map = new Map();
    for (const item of arr) {
        map.set(item.id, item); 
    }
    for(const item of arr) {
        if (map.get(item.parentId)) {
            let parent = map.get(item.parentId);
            parent.children = item;
            map.set(item.parentId, parent); 
        }
        else {
            result.push(item);
        }
    }
    return result;
}

3 場景問題

3.1 循環(huán)打印紅黃綠

問題:紅燈 3s 亮一次,綠燈 1s 亮一次倒彰,黃燈 2s 亮一次审洞;如何讓三個(gè)燈不斷交替重復(fù)亮燈?

function flash(type, time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(type);
            resolve();
        }, time);
    });
}

function run() {
    return flash('red', 3000)
        .then(() => flash('green', 1000))
        .then(() => flash('yellow', 2000))
        .then(() => run());
}

run();

3.2 判斷對象是否存在循環(huán)引用

解決方式:通過map的方式保存遞歸的對象待讳,判斷是否有循環(huán)引用芒澜。

function isCycle(obj, tem = {}) {
    for(let o in obj) {
        const v = obj[o];
        if (typeof v === 'object') {
            if (tem[v]) {
                return true;
            }
            tem[v] = true;
            if (isCycle(v, tem)) {
                return true;
            }
        }
    }
    return false;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市创淡,隨后出現(xiàn)的幾起案子痴晦,更是在濱河造成了極大的恐慌,老刑警劉巖琳彩,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件誊酌,死亡現(xiàn)場離奇詭異,居然都是意外死亡露乏,警方通過查閱死者的電腦和手機(jī)碧浊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘟仿,“玉大人箱锐,你說我怎么就攤上這事±徒希” “怎么了驹止?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長兴想。 經(jīng)常有香客問我幢哨,道長赡勘,這世上最難降的妖魔是什么嫂便? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮闸与,結(jié)果婚禮上毙替,老公的妹妹穿的比我還像新娘岸售。我一直安慰自己,他們只是感情好厂画,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布凸丸。 她就那樣靜靜地躺著,像睡著了一般袱院。 火紅的嫁衣襯著肌膚如雪屎慢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天忽洛,我揣著相機(jī)與錄音腻惠,去河邊找鬼。 笑死欲虚,一個(gè)胖子當(dāng)著我的面吹牛集灌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播复哆,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼欣喧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了梯找?” 一聲冷哼從身側(cè)響起唆阿,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎初肉,沒想到半個(gè)月后酷鸦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牙咏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年臼隔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妄壶。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡摔握,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丁寄,到底是詐尸還是另有隱情氨淌,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布伊磺,位于F島的核電站盛正,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏屑埋。R本人自食惡果不足惜豪筝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧续崖,春花似錦敲街、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至像吻,卻和暖如春峻黍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拨匆。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工奸披, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涮雷。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓阵面,卻偏偏與公主長得像,于是被迫代替她去往敵國和親洪鸭。 傳聞我的和親對象是個(gè)殘疾皇子样刷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容