JS能力測評經典題

每道題都寫多種解法,開闊思路。一共45道題。
由於牛客網oj不支持ES6語法,因此大多數寫法只給出傳統寫法。html

題目描述
找出元素 item 在給定數組 arr 中的位置es6

輸出描述:
若是數組中存在 item,則返回元素在數組中的位置,不然返回 -1
輸入例子:
indexOf([ 1, 2, 3, 4 ], 3)
輸出例子:
2正則表達式

// 通常寫法
function indexOf(arr, item) {
    for (var i = 0; i < arr.length; ++i) {
        if (item === arr[i]) {
            return i;
        }
    }
    return -1;
}

// 簡單粗暴版(由於js自帶的indexOf函數功能已經實現了)
function indexOf(arr, item) {
    return arr.indexOf(item);
}

// 每次比較後都將數組首元素去掉,同時計數器加1,直到找到元素item
function indexOf(arr, item) {
    var count = 0, len = arr.length;
    while (arr.length !== 0 && arr[0] !== item) {
        arr.shift();
        count++;
    }

    return count === len ? -1 : count;
}

// 較複雜的寫法(不建議使用)
function indexOf(arr, item) {
    var pos = arr.map(function(e, index) {
        return e === item ? index: -1;
    }).filter(function(e) {
        return e !== -1;
    });

    return pos.length === 0 ? -1 : pos[0];
}

// forEach加try-catch語句(不建議使用)
function indexOf(arr, item) {
    try {
        arr.forEach((e, i) => {
            if (e === item) {
                throw new Error(i);
            }
        } catch (err) {
            return err.message;
        }
        return -1;
    }
}

題目描述編程

計算給定數組 arr 中全部元素的總和
輸入描述:
數組中的元素均爲 Number 類型
輸入例子:
sum([ 1, 2, 3, 4 ])
輸出例子:
10segmentfault

// 通常寫法
function sum(arr) {
    var sum = 0;
    for (var i = 0; i < arr.length; ++i) {
        sum += arr[i];
    }
    return sum;
}

// 使用reduce,且將sum初始化爲0
function sum(arr) {
    return arr.reduce(function(sum, e) {
        return sum + e;
    }, 0);
}
// ES6寫法,且將reduce中傳的0省略,則sum在這裏至關於初始化爲arr的首元素
//【第一個sum爲函數名,其他爲函數內變量名】
const sum = (arr) => arr.reduce((sum, e) => sum + e);

題目描述數組

移除數組 arr 中的全部值與 item 相等的元素。不要直接修改數組 arr,結果返回新的數組
輸入例子:
remove([1, 2, 3, 4, 2], 2)
輸出例子:
[1, 3, 4]閉包

// 通常寫法
function remove(arr, item) {
    var tempArr = [];
    for (var i = 0; i < arr.length; ++i) {
        tempArr.push(arr[i]);
    }
    /* 對arr的拷貝可以使用一個技巧,即 tempArr = arr.slice(0);
       之後均採用這種寫法*/

    var index = tempArr.indexOf(item);
    while (index !== -1) {
        tempArr.splice(index, 1); // 每次刪一個元素
        index = tempArr.indexOf(item);
    }

    return tempArr;
}


// 使用filter
function remove(arr, item) {
    return arr.filter(function(e) {
        return e !== item;
    });
};
// ES6寫法
const remove = (arr, item) => arr.filter((e) => e !== item);

移除數組 arr 中的全部值與 item 相等的元素,直接在給定的 arr 數組上進行操做,並將結果返回app

輸入例子:
removeWithoutCopy([1, 2, 2, 3, 4, 2, 2], 2)
輸出例子:
[1, 3, 4]ide

// 通常寫法
function removeWithoutCopy(arr, item) {
    for (var i = 0; i < arr.length; ++i) {
        if (arr[i] === item) {
            arr.splice(i, 1);
            i--;
        };
    };

    return arr;
}

// 相似地
function removeWithoutCopy(arr, item) {
    var index = arr.indexOf(item);
    while (index !== -1) {
        arr.splice(index, 1);
        index = arr.indexOf(item);
    }

    return arr;
}

/* 由於filter會改變不修改數組自己,會返回一個新數組,因此此處不採用 */

題目描述wordpress

在數組 arr 末尾添加元素 item。不要直接修改數組 arr,結果返回新的數組
輸入例子:
append([1, 2, 3, 4], 10)
輸出例子:
[1, 2, 3, 4, 10]

function append(arr, item) {
    var tempArr = arr.slice(0);
    tempArr.push(item);

    return tempArr;
}

題目描述

刪除數組 arr 最後一個元素。不要直接修改數組 arr,結果返回新的數組
輸入例子:
truncate([1, 2, 3, 4])
輸出例子:
[1, 2, 3]

// 通常寫法
function truncate(arr) {
    var tempArr = arr.slice(0);
    tempArr.splice(arr.length - 1);

    return tempArr;
}

// 使用pop
function truncate(arr) {
    var tempArr = arr.slice(0);
    tempArr.pop();

    return tempArr;
}

題目描述

在數組 arr 開頭添加元素 item。不要直接修改數組 arr,結果返回新的數組
輸入例子:
prepend([1, 2, 3, 4], 10)
輸出例子:
[10, 1, 2, 3, 4]

// 使用splice添加元素
function prepend(arr, item) {
    var tempArr = arr.slice(0);
    tempArr.splice(0, 0, item);

    return tempArr;
}

// 直接使用unshift添加首元素方法
function prepend(arr, item) {
    var tempArr = arr.slice(0);
    tempArr.unshift(item);

    return tempArr;
}

題目描述

刪除數組 arr 第一個元素。不要直接修改數組 arr,結果返回新的數組
輸入例子:
curtail([1, 2, 3, 4])
輸出例子:
[2, 3, 4]

// 使用splice刪除元素
function curtail(arr) {
    var tempArr = arr.slice();
    tempArr.splice(0, 1);

    return tempArr;
}

// 直接使用shift刪除首元素方法
function curtail(arr) {
    var tempArr = arr.slice();
    tempArr.shift();

    return tempArr;
}

題目描述

合併數組 arr1 和數組 arr2。不要直接修改數組 arr,結果返回新的數組
輸入例子:
concat([1, 2, 3, 4], ['a', 'b', 'c', 1])
輸出例子:
[1, 2, 3, 4, 'a', 'b', 'c', 1]

// 簡單粗暴版,js已實現此函數功能
function concat(arr1, arr2) {
    var tempArr = arr1.slice(0);
    return tempArr.concat(arr2);
}

// 直接將arr2中的元素一個個push
function concat(arr1, arr2) {
    var tempArr = arr1.slice(0);
    arr2.forEach(function(e) {
        tempArr.push(e);
    });

    return tempArr;
}

// 簡化版,使用apply
function concat(arr1, arr2) {
    var tempArr = arr1.slice(0);
    [].push.apply(tempArr, arr2); // 簡寫版,可替換成下面一行,數組原型方法
    /* Array.prototype.push.apply(tempArr, arr2); */

    return tempArr;
}

題目描述

在數組 arr 的 index 處添加元素 item。不要直接修改數組 arr,結果返回新的數組
輸入例子:
insert([1, 2, 3, 4], 'z', 2)
輸出例子:
[1, 2, 'z', 3, 4]

// 使用splice添加元素
function insert(arr, item, index) {
    var tempArr = arr.slice(0);
    tempArr.splice(index, 0, item);

    return tempArr;
}

題目描述

統計數組 arr 中值等於 item 的元素出現的次數
輸入例子:
count([1, 2, 4, 4, 3, 4, 3], 4)
輸出例子:
3

// 通常寫法
function count(arr, item) {
    var count = 0;
    arr.forEach(function(e) {
        e === item ? count++ : 0;
    });

    return count;
}

// 使用ES6的for...of循環
function count(arr, item) {
    let cnt = 0;
    for (let e of arr) {
        e === item ? cnt++ : 0;
    }
    return cnt;
}

// 使用reduce,歸約寫法
function count(arr, item) {
   return arr.reduce(function(cnt, e) {
       return cnt + (e === item ? 1 : 0);
   }, 0);
}
// 使用ES6箭頭函數
const count = (arr, item) =>
    arr.reduce((cnt, e) =>
        cnt + (e === item ? 1 : 0), 0);

// 使用filter,返回一個新數組,其長度即爲所求
const count = (arr, item) => arr.filter(e => e === item).length;

題目描述
找出數組 arr 中重複出現過的元素

輸入例子:
duplicates([1, 2, 4, 4, 3, 3, 1, 5, 3]).sort()
輸出例子:
[1, 3, 4]

關於indexOf與lastIndexOf的文檔

// 通常寫法,排序以後判斷相鄰元素是否相等
function duplicates(arr) {
    var sortedArr = arr.sort();
    var tempArr = [];
    for (var i = 0; i < sortedArr.length; ++i) {
        if (sortedArr[i] === sortedArr[i + 1] &&
             tempArr.indexOf(sortedArr[i]) === -1) {
            tempArr.push(sortedArr[i]);
        }
    }

    return tempArr;
}

// indexOf和lastIndexOf的妙用
function duplicates(arr) {
    var tempArr = [];
    arr.forEach(function(e) {
       if (arr.indexOf(e) !== arr.lastIndexOf(e) &&
            tempArr.indexOf(e) === -1) {
           tempArr.push(e);
       }
    });

    return tempArr;
}

// 使用reduce
function duplicates(arr) {
    var tempArr = [];
    arr.forEach(function(e) {
        tempArr[e] = (tempArr[e] === undefined ? 1 : tempArr[e] + 1);
        /* 計算每一個元素出現次數 */
    });

    return tempArr.reduce(function(ret, e, item) {
        if (e && e !== 1 && ret.indexOf(item) === -1) {
            ret.push(item);
            /* 當元素存在,且出現次數不爲1,且未push進ret中時... */
        }
        return ret;
    }, []);
}

題目描述

爲數組 arr 中的每一個元素求二次方。不要直接修改數組 arr,結果返回新的數組
輸入例子:
square([1, 2, 3, 4])
輸出例子:
[1, 4, 9, 16]

// 通常寫法
function square(arr) {
    var tempArr = [];
    arr.forEach(function(e) {
        tempArr.push(e * e);
    });

    return tempArr;
}

// 使用map
function square(arr) {
    return arr.map(function(e) {
        return e * e;
    })
}
// ES6箭頭函數版
const square = arr => arr.map(e => e * e);

題目描述

在數組 arr 中,查找值與 item 相等的元素出現的全部位置
輸入例子:
findAllOccurrences('abcdefabc'.split(''), 'a').sort()
輸出例子:
[0, 6]

// 通常寫法(類C,不推薦)
function findAllOccurrences(arr, item) {
    var tempArr = [];
    for (var i = 0; i < arr.length; i++){
        if (arr[i] === item) {
            tempArr.push(i);
        }
    }

    return tempArr;
}

// 改進版
function findAllOccurrences(arr, item) {
    var tempArr = [];
    arr.forEach(function(e, index) {
        e !== item || tempArr.push(index);
    });

    return tempArr;
}

// 使用map和filter
function findAllOccurrences(arr, item) {
    return arr.map(function(ele, index) {
        return ele === item ? index : -1;
        /* 樣例返回結果爲[ -1, -1, -1, -1, -1, -1, -1, 0, 6 ] */
    }).filter(function(e) {
        return e !== -1;
        /* 過濾掉 e === -1 的狀況 */
    })
}
// ES6箭頭函數版
const findAllOccurrences = (arr, item) =>
    arr.map((ele, index) => ele === item ? index : -1).filter(e => e !== -1);

題目描述

給定的 js 代碼中存在全局變量,請修復

function globals() {
    myObject = {
      name : 'Jory'
    };
    return myObject;
}
/* 在JavaScript中,若是不使用var聲明變量,則該變量被視爲全局變量。*/

// 直接加var (在ES6標準中,最好替換成const或let)
function globals() {
    var myObject = {
      name : 'Jory'
    };

    return myObject;
}

// 把對象歸屬改成原型
function globals() {
    globals.prototype.myObject = {
        name : 'Jory'
    };

    return globals;
}

// 把對象改成匿名的
function globals() {
    return { name : 'Jory' };
}

題目描述

請修復給定的 js 代碼中,函數定義存在的問題

function functions(flag) {
    if (flag) {
      function getValue() { return 'a'; }
    } else {
      function getValue() { return 'b'; }
    }
    return getValue();
}

輸入例子:
functions(true)
輸出例子:
a

/* else中的語句至關於將if中的function重寫,所以不管flag爲什麼值,返回的方法始終爲重寫後的方
   法。將方法賦值給一個變量,方法就不會被重寫 */

// 將方法賦值給一個變量
function functions(flag) {
    var getValue = null;
    if (flag) {
        getValue = function () { return 'a'; }
    } else {
        getValue = function () { return 'b'; }
    }

    return getValue();
}

// 修改成閉包形式
function functions(flag) {
    if (flag) {
        return (function() { return 'a'; })();
    } else {
        return (function() { return 'b'; })();
    }
}

// 使用 ?: 判斷語句整合版
function functions(flag) {
    function getValue() {
        return flag ? 'a' : 'b';
    }

    return getValue();
}
// ES6箭頭函數形式(精簡版)
const functions = flag => flag ? 'a' : 'b';

題目描述

修改 js 代碼中 parseInt 的調用方式,使之經過所有測試用例

function parse2Int(num) {
    return parseInt(num);
}

輸入例子:
parse2Int('12'); parse2Int('12px'); parse2Int('0x12')
輸出例子:
12; 12; 0

/* parseInt(string, radix);
   當參數radix的值爲0,或沒有設置該參數時,parseInt()會根據 string 來判斷數字的基數。
   若是string以"0x"開頭,parseInt()會把string的其他部分解析爲十六進制的整數。
   若是string以0開頭,那麼ECMAScript3容許parseInt()的一個實現把其後的字符解析爲八進制
   或十六進制的數字。若是string以1~9的數字開頭,parseInt()將把它解析爲十進制的整數 */

// 將全部輸入轉換成十進制輸出
function parse2Int(num) {
    return parseInt(num, 10);
}

題目描述

判斷 val1 和 val2 是否徹底等同

function identity(val1, val2) {
    return val1 === val2;
}

題目描述

實現一個打點計時器,要求
一、從 start 到 end(包含 start 和 end),每隔 100 毫秒 console.log 一個數字,每次數字增幅爲 1
二、返回的對象中須要包含一個 cancel 方法,用於中止定時操做
三、第一個數須要當即輸出

setTimeout和setInterval的語法相同。它們都有兩個參數,一個是將要執行的代碼字符串,還有一個
是以毫秒爲單位的時間間隔,當過了那個時間段以後就將執行那段代碼。
不過這兩個函數仍是有區別的,setInterval在執行完一次代碼以後,通過了那個固定的時間間隔,它還
會自動重複執行代碼,而setTimeout只執行一次那段代碼。
window.setInterval("function", time); //設置一個超時對象,週期="交互時間"
window.setTimeout("function", time);  //設置一個超時對象,只執行一次,無週期
/* 中止定時 */
window.clearInterval(對象);   // 清除已設置的setInterval對象
window.clearTimeout(對象);    // 清除已設置的setTimeout對象

setInterval setTimeout clearInterval() clearTimeout()

// 通常寫法,使用setInterval
function count(start, end) {
    console.log(start++);

    var timer = setInterval(function() {
        if (start <= end) {
            console.log(start++);
        } else {
            clearInterval(timer);
        }
    }, 100);

    return {
        cancel: function() {
            clearInterval(timer);
        }
    }
}

// 用setTimeout模擬setInterval,遞歸寫法,表述較簡潔
function count(start, end) {
    if (start <= end) {
        console.log(start++);

        st = setTimeout(function() {
            count(start, end);
        }, 100);
    }

    return {
        cancel: function() {
            clearTimeout(st);
        }
    }
}

// 這種寫法不符合函數式編程的特色,不推薦
function count(start, end) {
    var timer = null;
    console.log(start);

    var obj = {
        timer: setInterval(function() {
            if (start <= end) {
                start++;
                console.log(start);
            } else {
                clearInterval(this.timer);
            }
        }, 100),
        cancel: function() {
          clearInterval(this.timer);
        }
    }

    return obj;
}

題目描述

實現 fizzBuzz 函數,參數 num 與返回值的關係以下:
一、若是 num 能同時被 3 和 5 整除,返回字符串 fizzbuzz
二、若是 num 能被 3 整除,返回字符串 fizz
三、若是 num 能被 5 整除,返回字符串 buzz
四、若是參數爲空或者不是 Number 類型,返回 false
五、其他狀況,返回參數 num
輸入例子:
fizzBuzz(15)
輸出例子:
fizzbuzz

// 通常寫法
function fizzBuzz(num) {
    if (num % 3 === 0 && num % 5 === 0) {
    /* 特殊地,可換爲 if (num % 15 === 0) */
        return 'fizzbuzz';
    } else if (num % 3 === 0) {
        return 'fizz';
    } else if (num % 5 === 0) {
        return 'buzz';
    }

    if (num === null || num === '' || typeof num !== 'number') {
        return false;
    }

    return num;
}

// 改進寫法
function fizzBuzz(num) {
    if (num === null || num === '' || typeof num !== 'number') {
        return false;
    }

    var result = '';
    if (num % 3 === 0) {
        result += 'fizz';
    }
    if (num % 5 === 0) {
        result += 'buzz';
    }

    return result ? result : num;
}

題目描述

將數組 arr 中的元素做爲調用函數 fn 的參數
輸入例子:
argsAsArray(function (greeting, name, punctuation) {return greeting + ', ' + name + (punctuation || '!');}, ['Hello', 'Ellie', '!'])
輸出例子:
Hello, Ellie!

// 直接法
function argsAsArray(fn, arr) {
    return fn(arr[0],arr[1],arr[2]);
}

/* 調用函數可使用call或者apply這兩個方法,區別在於call須要將傳給函數的參數明確寫出來,是
   多少參數就須要寫多少參數。而apply則將傳遞給函數的參數放入一個數組中,傳入參數數組便可 */
function argsAsArray(fn, arr) {
    return fn.apply(this, arr);
}

題目描述

將函數 fn 的執行上下文改成 obj 對象
輸入例子:
speak(function () {return this.greeting + ', ' + this.name + '!!!';}, {greeting: 'Hello', name: 'Rebecca'})
輸出例子:
Hello, Rebecca!!!

// apply
function speak(fn, obj) {
    return fn.apply(obj, []); // 第二個參數可省略
}

// call
function speak(fn, obj) {
    return fn.call(obj);
}

// bind
function speak(fn, obj) {
    return fn.bind(obj)();
}

題目描述

實現函數 functionFunction,調用以後知足以下條件:
一、返回值爲一個函數 f
二、調用返回的函數 f,返回值爲按照調用順序的參數拼接,拼接字符爲英文逗號加一個空格,即 ', '
三、全部函數的參數數量爲 1,且均爲 String 類型
輸入例子:
functionFunction('Hello')('world')
輸出例子:
Hello, world

// 通常寫法
function functionFunction(str) {
    function f(s) {
        return str + ', ' + s; // 可替換爲 return [str, s].join(', '); 
    }

    return f;
}

// 精簡版,省略內部命名函數
const functionFunction = str => s => [str, s].join(', ');

題目描述

實現函數 makeClosures,調用以後知足以下條件:
一、返回一個函數數組 result,長度與 arr 相同
二、運行 result 中第 i 個函數,即 result[i](),結果與 fn(arr[i]) 相同
輸入例子:

var arr = [1, 2, 3]; 
var square = function (x) { 
    return x * x; 
}; 
var funcs = makeClosures(arr, square); 
funcs[1]();

輸出例子:
4

理解閉包

// 這種寫法比較繞(多層嵌套)
function makeClosures(arr, fn) {
    var result = [];
    arr.forEach(function(e) {
        result.push(function(num) {
            return function() {
                return fn(num);
            };
        }(e));
    });

    return result;
}

// 較簡潔版(通常按這種方式)
function makeClosures(arr, fn) {
    var result = [];
    arr.forEach(function(e) {
        result.push(function() {
            return fn(e);
        });
    });

    return result;
}

// bind的妙用(推薦寫法)
function makeClosures(arr, fn) {
    var result = [];
    arr.forEach(function(e) {
        result.push(fn.bind(this, e));
    });

    return result;
}

/* 爲了更清晰地做對比,對這幾種寫法分別用箭頭函數表示 */
// 1
function makeClosures(arr, fn) {
    let result = [];
    arr.forEach(e => result.push(num => () => fn(num))(e));
    return result;
}
// 2
function makeClosures(arr, fn) {
    let result = [];
    arr.forEach(e => result.push((e => () => fn(e))(e)));
    return result;
} 
// 3
function makeClosures(arr, fn) {
    let result = [];
    arr.forEach(e => result.push(fn.bind(null, e))); 
    return result;
}

題目描述

已知函數 fn 執行須要 3 個參數。請實現函數 partial,調用以後知足以下條件:
一、返回一個函數 result,該函數接受一個參數
二、執行 result(str3) ,返回的結果與 fn(str1, str2, str3) 一致
輸入例子:
var sayIt = function(greeting, name, punctuation) { return greeting + ', ' + name + (punctuation || '!'); }; partial(sayIt, 'Hello', 'Ellie')('!!!');
輸出例子:
Hello, Ellie!!!

關於js中 call、apply、bind 的用法可參考這篇博客
// 通常寫法
function partial(fn, str1, str2) {
    function result(str3) {
        return fn(str1, str2, str3);
    }

    return result;
}

// call
function partial(fn, str1, str2) {
    function result(str3) {
        return fn.call(this, str1, str2, str3);
    }

     return result;
}

// apply(這裏只是爲了對照)
function partial(fn, str1, str2) {
    function result(str3) {
        return fn.apply(this, [str1, str2, str3]);
    }

    return result;
}

// 這個bind會生成一個新函數對象, 它的str1, str2參數都定死了, str3未傳入, 一旦傳入就會執行
function partial(fn, str1, str2) {
    return fn.bind(this, str1, str2); // 或 return fn.bind(null, str1, str2);
}

// bind同上, 多了一步, 把str3傳入的過程寫在另外一個函數裏面, 而另外一個函數也有str1, str2參數
function partial(fn, str1, str2) {
    function result(str3) {
        return fn.bind(this, str1, str2)(str3);
    }

    return result;
}

// 匿名函數
function partial(fn, str1, str2) {
    return function(str3) {
        return fn(str1, str2, str3);
    }
}
// ES6
const partial = (fn, str1, str2) => str3 => fn(str1, str2, str3);

題目描述

函數 useArguments 能夠接收 1 個及以上的參數。請實現函數 useArguments,返回全部調用參數相加後的結果。本題的測試參數所有爲 Number 類型,不需考慮參數轉換。
輸入例子:
useArguments(1, 2, 3, 4)
輸出例子:
10

關於arguments的介紹

// 通常寫法,直接利用arguments只有length屬性的特色
function useArguments() {
    var sum = 0;
    for (var i = 0; i < arguments.length; ++i) {
        sum += arguments[i];
    }

    return sum;
}

// call
function useArguments() {
    var arr = [].slice.call(arguments); // 轉成數組 ([]爲Array.prototype的語法糖)
    return arr.reduce(function(a, b) {
        return a + b;
    });
}
/* call, bind, apply會改變生成函數對象的this, 使得arguments能夠直接使用數組的方法,
   因此也可不轉換成數組而直接使用reduce */

// call同上, 精簡版
function useArguments() {
    return [].reduce.call(arguments, function(a, b) {
        return a + b;
    });
}

// bind
function useArguments() {
    return [].reduce.bind(arguments, function(a, b) {
        return a + b;
    })();
}

// apply
function useArguments() {
    return [].reduce.apply(arguments, [function(a, b) {
        return a + b;
    }]);
}

// eval的妙用,但不推薦使用eval
function useArguments() {
    var arr = Array.prototype.slice.call(arguments);
    return eval(arr.join('+'));
}

題目描述

實現函數 callIt,調用以後知足以下條件
一、返回的結果爲調用 fn 以後的結果
二、fn 的調用參數爲 callIt 的第一個參數以後的所有參數
輸入例子:
var a = 1; var b = 2; var test = function (first, second) { return first === a && second === b;}; callIt(test, a, b);
輸出例子:
true

箭頭函數的arguments 剩餘參數(rest parameter)

// slice
function callIt(fn) {
    var arr = [].slice.call(arguments, 1); 
    /* 將arguments轉成數組並只截取從1開始以後的全部元素 */
    return fn.apply(this, arr);
}

// shift
function callIt(fn) {
    return [].shift.call(arguments).apply(null, arguments);
    /* [].shift.call(arguments)返回了第一個參數fn, 由於這裏fn等價於arguments[0] */
}

// ES6語法糖
const callIt = (fn, ...args) => fn(...args);

題目描述

實現函數 partialUsingArguments,調用以後知足以下條件:
一、返回一個函數 result
二、調用 result 以後,返回的結果與調用函數 fn 的結果一致
三、fn 的調用參數爲 partialUsingArguments 的第一個參數以後的所有參數以及 result 的調用參數
輸入例子:
var a = 1; var b = 2; var c = 3; var d = 4;var test = function (first, second, third, forth) {return first + second + third + forth;};partialUsingArguments(test, a, b)(c, d);
輸出例子:
10

function partialUsingArguments(fn) {
    var arr = [].slice.call(arguments, 1); 
    /* arr是由partialUsingArguments傳的arguments轉換而來 */
    
    function result() {
        var arrFromResult = [].slice.call(arguments);
        /* arrFromResult則從函數result中傳的arguments轉換, 因此不能在result外獲取 */
        return fn.apply(null, arr.concat(arrFromResult));
    }

    return result;
}

// 稍微簡化,跟上面差很少
function partialUsingArguments(fn) {
    var arr = [].slice.call(arguments, 1);
    
    return function() {
        return fn.apply(this, arr.concat([].slice.call(arguments)));
    }
}

題目描述

已知 fn 爲一個預約義函數,實現函數 curryIt,調用以後知足以下條件:
一、返回一個函數 a,a 的 length 屬性值爲 1(即顯式聲明 a 接收一個參數)
二、調用 a 以後,返回一個函數 b, b 的 length 屬性值爲 1
三、調用 b 以後,返回一個函數 c, c 的 length 屬性值爲 1
四、調用 c 以後,返回的結果與調用 fn 的返回值一致
五、fn 的參數依次爲函數 a, b, c 的調用參數
輸入例子:
var fn = function (a, b, c) {return a + b + c}; curryIt(fn)(1)(2)(3);
輸出例子:
6

JS中的柯里化(currying)

// apply
function curryIt(fn) {
    var arr = [];
    return function(a) {
        arr.push(a);
        return function(b) {
            arr.push(b);
            return function(c) {
                arr.push(c);
                return fn.apply(this, arr);
            }
        }
    }
}

// 推薦寫法
function curryIt(fn) {
    return function(e1) {
        return function(e2) {
            return function(e3) {
                return fn(e1, e2, e3); // return fn.call(this, e1, e2, e3); 與之等價
            }
        }
    }
}
// 箭頭函數
const curryIt = fn => e1 => e2 => e3 => fn(e1, e2, e3);

題目描述

返回參數 a 和 b 的邏輯或運算結果
輸入例子:
or(false, true)
輸出例子:
true

function or(a, b) {
    return a || b;
}

題目描述

返回參數 a 和 b 的邏輯且運算結果
輸入例子:
and(false, true)
輸出例子:
false

function and(a, b) {
    return a && b;
}

題目描述

完成函數 createModule,調用以後知足以下要求:
一、返回一個對象
二、對象的 greeting 屬性值等於 str1, name 屬性值等於 str2
三、對象存在一個 sayIt 方法,該方法返回的字符串爲 greeting屬性值 + ', ' + name屬性值

// 推薦寫法
function createModule(str1, str2) {
    return {
        greeting: str1,
        name: str2,
        sayIt: function() {
            return [this.greeting, this.name].join(', ');
        }
    }
}

// Constructor grammer
function createModule(str1, str2) {
    function Obj() {
        this.greeting = str1;
        this.name = str2;
        this.sayIt = function() {
            return this.greeting + ', ' + this.name;
        }
    }
    
    return new Obj();   
}

題目描述

獲取數字 num 二進制形式第 bit 位的值。注意:
一、bit 從 1 開始
二、返回 0 或 1
三、舉例:2 的二進制爲 10,第 1 位爲 0,第 2 位爲 1
輸入例子:
valueAtBit(128, 8)
輸出例子:
1

// 推薦寫法 (時間複雜度是O(log bit))
function valueAtBit(num, bit) {
    return (num & Math.pow(2, bit - 1)) === 0 ? 0 : 1;
}

// 利用運算符特性,簡潔寫法 (時間複雜度O(n))
function valueAtBit(num, bit) {
    return num >> (bit - 1) & 1;
}

// 轉成字符串 (不推薦)
function valueAtBit(num, bit) {
    var s = num.toString(2);
    var len = s.length;
    return parseInt(s[len - bit]);
}

題目描述

給定二進制字符串,將其換算成對應的十進制數字
輸入例子:
base10('11000000')
輸出例子:
192

// parseInt(string, radix) 的可選參數是操做數的進制說明,不是目標的進制。
function base10(str) {
    return parseInt(str, 2);
}

題目描述

將給定數字轉換成二進制字符串。若是字符串長度不足 8 位,則在前面補 0 到滿8位。
輸入例子:
convertToBinary(65)
輸出例子:
01000001

// 前三種都是採用拼接方法
function convertToBinary(num) {
    var s = num.toString(2);
    var len = s.length;
    if (len < 8) {
        s = '0000000'.slice(0, 8 - len) + s;
    }
    
    return s;
}

function convertToBinary(num) {
    var s = num.toString(2);
    while (s.length < 8) {
        s = '0' + s;
    }
     
    return s;
}

function convertToBinary(num) {
    var s = num.toString(2);
    return s.length < 8 ? new Array(8 - s.length + 1).join('0').concat(s) : s;
}

// 推薦寫法, 若是長度過長, 則截取後8位(倒數第8位開始到最後1位)
function convertToBinary(num) {
    var s = num.toString(2);
    return s.length < 8 ? ('00000000' + s).slice(-8) : s;
}

題目描述

求 a 和 b 相乘的值,a 和 b 多是小數,須要注意結果的精度問題
輸入例子:
multiply(3, 0.0001)
輸出例子:
0.0003

String.prototype.substring()

Number.prototype.toFixed()

// 推薦寫法
function multiply(a, b) {
    a = a.toString();
    b = b.toString();
    var aLen = a.substring(a.indexOf('.') + 1).length;
    var bLen = b.substring(b.indexOf('.') + 1).length; 
    
    return (a * b).toFixed(Math.max(aLen, bLen));
    /* 本題未說明保留小數位數, 這裏假定得出的結果不含多餘的0, 即0.0003000...需轉成0.0003 */
}

題目描述

將函數 fn 的執行上下文改成 obj,返回 fn 執行後的值
輸入例子:
alterContext(function() {return this.greeting + ', ' + this.name + '!'; }, {name: 'Rebecca', greeting: 'Yo' })
輸出例子:
Yo, Rebecca!

/* 將函數fn的執行上下文改成obj對象, 只須要將obj做爲call或apply的第一個參數傳入便可 */
// call
function alterContext(fn, obj) {
    return fn.call(obj); // 這裏的第二個參數無關緊要, 若有, 則做爲fn的參數(下同)
}

// apply
function alterContext(fn, obj) {
  return fn.apply(obj); 
}

// bind
function alterContext(fn, obj) {
  return fn.bind(obj)(); // .bind()返回的是一個函數, 須要當即執行 
}

題目描述

給定一個構造函數 constructor,請完成 alterObjects 方法,將 constructor 的全部實例的 greeting 屬性指向給定的 greeting 變量。
輸入例子:
var C = function(name) {this.name = name; return this;}; var obj1 = new C('Rebecca'); alterObjects(C, 'What's up'); obj1.greeting;
輸出例子:
What's up

繼承與原型鏈(prototype chain)

/* 每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個
   指向原型對象的內部指針 */

function alterObjects(constructor, greeting) {
    constructor.prototype.greeting = greeting;
}

題目描述

找出對象 obj 不在原型鏈上的屬性(注意這題測試例子的冒號後面也有一個空格~)
一、返回數組,格式爲 key: value
二、結果數組不要求順序
輸入例子:
var C = function() {this.foo = 'bar'; this.baz = 'bim';}; C.prototype.bop = 'bip'; iterate(new C());
輸出例子:
["foo: bar", "baz: bim"]

Object.getOwnPropertyNames()
Object.keys()
Object.prototype.hasOwnProperty()
// 前兩種均使用map (推薦寫法)
function iterate(obj) {
    return Object.getOwnPropertyNames(obj).map(function(key) {
        return key + ': ' + obj[key];
    });
}

function iterate(obj) {
    return Object.keys(obj).map(function(key) {
        return key + ': ' + obj[key];
    });
}

/*用for-in遍歷可枚舉的屬性, 用hasOwnProperty()方法判斷是不是自有屬性(即不在原型鏈上)*/
function iterate(obj) {
    var arr = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            arr.push(key + ': ' + obj[key]);
        }
    }
    
    return arr;
}

如下爲正則表達式相關題目

能夠經過下面兩種方法建立一個正則表達式:

  1. 使用一個正則表達式字面量,以下所示:

  2. re = /ab+c/;

正則表達式字面量在腳本加載後編譯。若你的正則表達式是常量,使用這種方式能夠得到更好的性能。

  1. 調用RegExp對象的構造函數,以下所示:

  2. re = new RegExp("ab+c");

使用構造函數,提供了對正則表達式運行時的編譯。當你知道正則表達式的模式會發生改變, 或者你事先並不瞭解它的模式或者是從其餘地方(好比用戶的輸入),獲得的代碼這時比較適合用構造函數的方式。

///

題目描述

給定字符串 str,檢查其是否包含數字,包含返回 true,不然返回 false
輸入例子:
containsNumber('abc123')
輸出例子:
true

\d 匹配一個數字, 等價於[0-9]。
例如,  /\d/ 或者 /[0-9]/ 匹配 "B2 is the suite number." 中的'2'。
test()方法執行一個檢索,用來查看正則表達式與指定的字符串是否匹配。返回true或false。
function containsNumber(str) {
    return /\d/.test(str);
}

題目描述

給定字符串 str,檢查其是否包含連續重複的字母(a-zA-Z),包含返回 true,不然返回 false
輸入例子:
containsRepeatingLetter('rattler')
輸出例子:
true

[xyz] 一個字符集合, 匹配方括號的中任意字符。可使用破折號(-)來指定一個字符範圍。
對於點(.)和星號(*)這樣的特殊符號在一個字符集中沒有特殊的意義。他們沒必要進行轉義,不過轉義也是起做用的。
例如,[abcd] 和[a-d]是同樣的。他們都匹配"brisket"中的‘b’,也都匹配「city」中的‘c’。
/[a-z.]+/ 和/[\w.]+/都匹配「test.i.ng」中的全部字符。

(x) 匹配 'x' 而且記住匹配項,就像下面的例子展現的那樣。括號被稱爲"捕獲括號"。
模式/(foo) (bar) \1 \2/中的'(foo)'和'(bar)'匹配並記住字符串'foo bar foo bar'中前兩個單詞。
模式中的 \1 和 \2 匹配字符串的後兩個單詞。注意 \一、\二、\n是用在正則表達式的匹配環節。
在正則表達式的替換環節,則要使用像 $一、$二、$n 這樣的語法,例如,
'bar foo'.replace( /(...) (...)/, '$2 $1' )。
function containsRepeatingLetter(str) {
    return /([a-zA-Z])\1/.test(str);
}

題目描述

給定字符串 str,檢查其是否以元音字母結尾
一、元音字母包括 a,e,i,o,u,以及對應的大寫
二、包含返回 true,不然返回 false
輸入例子:
endsWithVowel('gorilla')
輸出例子:
true

$ 匹配輸入的結束。若是多行標示被設置爲true,那麼也匹配換行符前的位置。
例如,/t$/ 並不會匹配 "eater" 中的 't',可是會匹配 "eat" 中的 't'。

經過標誌進行高級搜索
正則表達式有四個可選參數進行全局和不分大小寫搜索。
這些參數既能夠單獨使用也能夠一塊兒使用在任何順序和包含正則表達式的部分中。

正則表達式標誌
標誌    描述
g      全局搜索。
i      不區分大小寫搜索。
m      多行搜索。
y      執行「粘性」搜索,匹配從目標字符串的當前位置開始,可使用y標誌。
function endsWithVowel(str) {
    return /[aeiou]$/i.test(str);
}

題目描述

給定字符串 str,檢查其是否包含連續3個數字
一、若是包含,返回最新出現的3個數字的字符串
二、若是不包含,返回 false
輸入例子:
captureThreeNumbers('9876543')
輸出例子:
987

String.prototype.match()

function captureThreeNumbers(str) {
    var arr = str.match(/\d{3}/); // 尋找三個數字字符 \d{3}
    return arr ? arr[0] : false;
}

題目描述

給定字符串 str,檢查其是否符合以下格式
一、XXX-XXX-XXXX
二、其中 X 爲 Number 類型
輸入例子:
matchesPattern('800-555-1212')
輸出例子:
true

^ 匹配輸入的開始。若是多行標誌被設置爲true,那麼也匹配換行符後緊跟的位置。
例如,/^A/ 並不會匹配 "an A" 中的 'A',可是會匹配 "An E" 中的 'A'。
當 '^' 做爲第一個字符出如今一個字符集合模式時,它將會有不一樣的含義。
function matchesPattern(str) {
    return /^(\d{3}-){2}\d{4}$/.test(str);
}

題目描述

給定字符串 str,檢查其是否符合美圓書寫格式
一、以 $ 開始
二、整數部分,從個位起,滿 3 個數字用 , 分隔
三、若是爲小數,則小數部分長度爲 2
四、正確的格式如:$1,023,032.03 或者 $2.03,錯誤的格式如:$3,432,12.12 或者 $34,344.3
輸入例子:
isUSD('$20,933,209.93')
輸出例子:
true

? 匹配前面一個表達式0次或者1次。等價於 {0,1}。
例如,/e?le?/ 匹配 'angel' 中的 'el',和 'angle' 中的 'le' 
(注意第二個 ? 前面的匹配表達式是 e 而不是 le) 以及 'oslo' 中的'l'。

若是緊跟在任何量詞 *、 +、? 或 {} 的後面,將會使量詞變爲非貪婪的(匹配儘可能少的字符),和缺省
使用的貪婪模式(匹配儘量多的字符)正好相反。
例如,對 "123abc" 應用 /\d+/ 將會返回 "123",若是使用 /\d+?/,那麼就只會匹配到 "1"。
還能夠運用於向前斷言 正向確定查找x(?=y) 和 正向否認查找x(?!y) 。

* 匹配前一個表達式0次或屢次。等價於 {0,}。
例如,/bo*/會匹配 "A ghost boooooed" 中的 'booooo' 和 "A bird warbled" 中的 'b', 
可是在 "A goat grunted" 中將不會匹配任何東西。

. (小數點)匹配  除了換行符(\n)以外的任何單個字符。
例如, /.n/將會匹配"nay, an apple is on the tree"中的'an'和'on', 可是不會匹配 'nay'。
function isUSD(str) {
    return /^\$\d{1,3}(,\d{3})*(\.\d{2})?$/.test(str);
}

若有錯誤,懇請指正,也歡迎各位大佬貢獻出更好的解法

相關文章
相關標籤/搜索