[javascript]練習題整理(持續更新)

去重
const arr = [1,1,1,1,1,1,3,3,3,3,32,2,2,2,2,3,3,4,-1,-10,-10,-1,4,4,5,5,9]

// set方式去重
// 不改變源數組的數據
console.log([...new Set(arr)])

// includes方式去重,  時間複雜度 O(n)
function uniq(arr) {
    let _result = []
    for(let i=0; i < arr.length; i++) {
        if (!_result.includes(arr[i])) {
            _result.push(arr[i])
        }
    }
    return _result
}
console.log(uniq(arr))
冒泡排序

let arr = [1,2,5,3,1,6,7,3,4,10,12,3,21]

function bubbleSort(arr) {
    // 淺克隆, 對外部傳入的參數不進行更改, 保證函數是一個純函數
    let _arr = [].concat(arr)
    // 核心邏輯
    for(let i=0; i<_arr.length -1; i++) {
        for(let j=0; j<_arr.length-i-1; j++) {
            if (_arr[j] > _arr[j+1]) {
                let temp = _arr[j]
                _arr[j] = _arr[j + 1]
                _arr[j + 1] = temp
            }
        }
    }
    return _arr
}

console.log(bubbleSort(arr))
快速排序(二分法)
let arr = [300,432,1342,543,23,656,45,6465,4345,232,87,97,754,345]

function quickSort(arr) {

    if(arr.length <= 1) {
        return arr
    }

    const pivot = arr[0]
    let bigger = []
    let smaller = []

    for(let i=1; i<arr.length; i++) {
        if (arr[i] > pivot) {
            bigger.push(arr[i])
        }
    }

    for(let i=1; i<arr.length; i++) {
        if (arr[i] < pivot) {
            smaller.push(arr[i])
        }
    }
    return quickSort(smaller).concat(pivot, quickSort(bigger))
}

console.log(quickSort(arr))
函數柯里化
案例一: 
function curry(fn) {
    return function() {
        let arg = arguments
        return function() {
            return fn(...arg, ...arguments)
        }
    }
}

function fn(a,b,c,d) {
    return a+b+c+d
}

let fun = curry(fn)
let fun2 = fun(1,2,3)
console.log(fun2(5))

案例二: 
let fn = a => b => c => a+b+c
console.log(fn(1)(2)(3))
數組扁平化
let arr = [0,[3,4,5],[[[[12,5,6,7,54,34],43,34],33]], {a:1}]


function flatten(arr) {
    let _arr = []
    for(let i=0; i<arr.length; i++) {
        const leixing = Object.prototype.toString.call(arr[i])
        if (leixing !== '[object Array]') {
            _arr.push(arr[i])
        } else {
            _arr = _arr.concat(flatten(arr[i]))
        }
    }
    return _arr
}

console.log(flatten(arr))
原型鏈上擴展方法
Array.prototype.max =  function max() {
    console.log(this)
    return Math.max.apply(Math, this)
}
let array = [1,2,3,4]
console.log(array.max())
深克隆
let arr = [1,2,3,[4,5,6], {a:1}]

function deepClone(o) {
    if (
        typeof o == 'number'
        ||
        typeof o == 'string'
        ||
        typeof o == 'boolean'
        ||
        typeof o == 'undefined'
    ) {
        return o
    } else if(Array.isArray(o)) {
        let _arr = []
        for(let i=0; i<o.length; i++) {
            _arr.push(deepClone(o[i]))
        }
        return _arr
    } else if(typeof o == 'object') {
        let _o = {}
        for(let k in o) {
            _o[k] = deepClone(o[k])
        }
        return _o
    }
}

let deep = deepClone(arr)
console.log(arr[3] == deep[3]) // false
樣本篩選函數
// 功能: 傳入一個數值, 隨機生成指定範圍內的樣本數據
// 參數: 樣本個數
// start: 樣本起始數值
// end: 樣本結束數值
function sample(num, start, end) {
    end -= 1
    let _arr = []
    while(num != _arr.length){
        let data = parseInt(Math.random() * end) + start
        if (!_arr.includes(data)) {
            _arr.push(data)
        }
    }
    return _arr
}
console.log(sample(30, 2, 32))
//  輸出結果
//   [
//     9, 27, 18, 28, 24, 13, 31, 11,  6,
//     19,  7, 17, 21, 26, 30, 22,  8, 25,
//     10,  3,  2,  5,  4, 12, 20, 14, 29,
//     15, 32, 23
//   ]
字符串反轉函數
let str = 'abcde'
function myReverse(str) {
    return str.split('').reverse().join('')
}

let res = myReverse(str)
console.log(res)

偏函數
偏函數的作用: 調用之後能夠獲得一個特定功能的函數
// 需求: 實現一個檢查類型的偏函數
function checkType(type) {
    return function(o) {
        return Object.prototype.toString.call(o) == `[object ${type}]`
    }
}

let checkIsArray = checkType('Array')
console.log(checkIsArray([1,2,3]))
// 輸出結果
// true
閉包
閉包的特點: 調用永久記住當前作用域的變量

案例一: 
var a = 2

function foo() {
    var a = 1
    function bar() {
        console.log(a)
    }
    bar()
}
foo()
//輸出結果
//1

案例二: 
var a = 1
function bar() {
    console.log(a)
}

(function(fn) {
    var a = 2
    fn()
})(bar)
// 輸出結果
// 1
箭頭函數
// 箭頭函數this跟定義時上下文永遠綁定
// 普通函數的this, 視運行環境而改變
function fun() {
    return () => {
        console.log(this)
    }
}

let laowang = {name: 'laowang'}
let xiaoliu = {name: 'xiaoliu'}

let arrowFun = fun.call(laowang)

arrowFun() // { name: 'laowang' }

arrowFun.call(xiaoliu) // { name: 'laowang' }

arrowFun = arrowFun.bind(xiaoliu)
arrowFun() // { name: 'laowang' }
函數新特徵
// 函數非嚴格模式下實參與實參列表的關係
function fun(a, b) {
    a = (typeof a !== 'undefined') ? a : 10
    b = (typeof b !== 'undefined') ? b : 20

    console.log(a == arguments[0])
    console.log(b == arguments[1])

    a = 123
    b = 456

    console.log(a == arguments[0])
    console.log(b == arguments[1])
}
fun(1, 2)
// 輸出結果
// true
// true
// true
// true

// 函數嚴格模式下實參與實參列表的關係
function fun(a, b) {
    'use strict'
    a = (typeof a !== 'undefined') ? a : 10
    b = (typeof b !== 'undefined') ? b : 20

    console.log(a == arguments[0])
    console.log(b == arguments[1])

    a = 123
    b = 456

    console.log(a == arguments[0])
    console.log(b == arguments[1])
}

fun(1, 2)
// true
// true
// false
// false

// 函數改良
// 這種方式跟非嚴格模式下的執行結果是一致的
function fun(a=10, b=20) {
    console.log(a == arguments[0])
    console.log(b == arguments[1])

    a = 123
    b = 456

    console.log(a == arguments[0])
    console.log(b == arguments[1])
}

fun(1, 2)
// true
// true
// false
// false
暫時性死區
解釋: 變量在定義之後, 但沒有聲明的情況下, 是暫時不能訪問的
// 案例一: 函數後面的默認參數可以訪問前面的參數
// 實參其實相當於使用 let來聲明一個變量
function foo(a) {
    return a + 5
}

function fun(a, b = foo(a)) {
    console.log(a + b)
}

fun(1) // 7
fun(1, 2) // 3

// 案例二: 函數後面的參數無法訪問前面參數的值
function add(a = b, b) {
    return a + b
}
console.log(add(1, 2)) // 3
console.log(add(undefined, 2)) // ReferenceError: Cannot access 'b' before initialization
展開運算符
// 不使用展開運算符
let arr = [1,2,3,4]
let max = Math.max.apply(null,arr)
console.log(max)

// 改進
let arr = [1,2,3,4]
let max = Math.max(...arr)
console.log(max)
爲什麼使用嚴格模式
參考資料: https://www.runoob.com/js/js-strict.html
use strict解釋: 爲什麼使用嚴格模式:

消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行爲;
消除代碼運行的一些不安全之處,保證代碼運行的安全;
提高編譯器效率,增加運行速度;
爲未來新版本的Javascript做好鋪墊。
"嚴格模式"體現了Javascript更合理、更安全、更嚴謹的發展方向,包括IE 10在內的主流瀏覽器,都已經支持它,許多大項目已經開始全面擁抱它。

另一方面,同樣的代碼,在"嚴格模式"中,可能會有不一樣的運行結果;一些在"正常模式"下可以運行的語句,在"嚴格模式"下將不能運行。掌握這些內容,有助於更細緻深入地理解Javascript,讓你變成一個更好的程序員。
迭代器
// 需求: 封裝一個迭代器
function arrIterator(arr) {
    let i = 0
    return {
        next: function() {
            let done = i > arr.length - 1 ? true : false
            let value = !done ? arr[i++] : 'undefined'
            return {
                done,
                value
            }
        }
    }
}

let arr = [1,2,3,4,5]
let iterator = arrIterator(arr)
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

// 輸出結果
// { done: false, value: 1 }
// { done: false, value: 2 }
// { done: false, value: 3 }
// { done: false, value: 4 }
// { done: false, value: 5 }
// { done: true, value: 'undefined' }
生成器
// 生成器
// 作用: 用於生成迭代器
function *generator(arr) {
    for(let i=0; i<arr.length; i++) {
        yield arr[i]
    }
}

let arr = [1,2,3,4,5]
const arrIterator = generator(arr)
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())

// 生成器
// 作用: 用於生成迭代器
// 案例一
function *generator(arr) {
    for(let i=0; i<arr.length; i++) {
        yield arr[i]
    }
}

let arr = [1,2,3,4,5]
const arrIterator = generator(arr)
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())

// 輸出結果
// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: 4, done: false }
// { value: 5, done: false }
// { value: undefined, done: true }


// 案例二
// 生成器可以yield 一個Promise實例對象
function *generator() {
    yield sumAfter1000ms(1,2).then(res => console.log(res))
    yield sumAfter1000ms(2,2).then(res => console.log(res))
}

function sumAfter1000ms(a,b) {
    return new Promise((resolve, reject) => {
        setTimeout(function(){
            resolve(a+b)
        }, 2000)
    })
}

const iterator = generator()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

// 輸出結果
// { value: Promise { <pending> }, done: false }
// { value: Promise { <pending> }, done: false }
// { value: undefined, done: true }
// 3
// 4
Promise
promise作用: 
- 解決毀掉地獄的問題
- 使代碼調用更加清晰易懂

promise的三種狀態: 
- pending
- resolve
- reject. 

promise特點: 
- 使用resolve和reject封裝結果回調函數
- Promise的實例會調用.then方法

// 案例一
// 不使用promise的情況
function fun(a, b, cb) {
    setTimeout(function(){
        return cb(a + b)
    }, 2000)
}

fun(1,2, res => {
    console.log(res)
    fun(3,4, res => {
        console.log(res)
        fun(4, 5, res => {
            console.log(res)
        })
    })
})

// 案例二: 使用promise的寫法
function sum(a,b) {
    return new Promise((resolve, reject) => {
        setTimeout(function() {
            resolve(a + b)
        }, 2000)
    })
}

sum(1,2) 
.then(res => {
    console.log(res)
})

// 案例三: 使用promise寫法封裝一個讀文件操作函數
const fs = require('fs')
function readFile(filename) {
    return new Promise((resolve, reject) => {
        fs.readFile(filename, (err, res) => {
            if (err) {
                reject(new Error('所讀的文件不存在'))
                return
            } 
            resolve(res.toString())
        })
    })
}

readFile('./1.txt').then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})
async await
await後面緊跟的是一個Promise對象

function bar() {
    setTimeout(() => {
        console.log('hello')
    }, 2000);
}

async function fun(){
    let res = await bar()
    return res
}

console.log(fun())
// 輸出結果
// Promise { <pending> }
// hello

// 變形
function bar(a,b) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(a+b)
        }, 2000);
    })
}

async function fun(){
    let res = await bar(1,2)
    let res2 = await bar(3,4)
    return {res, res2}
}

fun().then(res => {
    console.log(res)
})

// 輸出結果
// { res: 3, res2: 7 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章