久久综合九色综合97婷婷-美女视频黄频a免费-精品日本一区二区三区在线观看-日韩中文无码有码免费视频-亚洲中文字幕无码专区-扒开双腿疯狂进出爽爽爽动态照片-国产乱理伦片在线观看夜-高清极品美女毛茸茸-欧美寡妇性猛交XXX-国产亚洲精品99在线播放-日韩美女毛片又爽又大毛片,99久久久无码国产精品9,国产成a人片在线观看视频下载,欧美疯狂xxxx吞精视频

有趣生活

當前位置:首頁>職場>前端開發技術面試題(前端JS高階面試題)

前端開發技術面試題(前端JS高階面試題)

發布時間:2024-01-24閱讀(16)

導讀1.如果咱們想要確保對象被深凍結,就必須創建一個遞歸函數來凍結對象類型的每個屬性:,我來為大家科普一下關于前端開發技術面試題?下面希望有你要的答案,我們一起....

1. 如果咱們想要確保對象被深凍結,就必須創建一個遞歸函數來凍結對象類型的每個屬性:,我來為大家科普一下關于前端開發技術面試題?下面希望有你要的答案,我們一起來看看吧!

前端開發技術面試題(前端JS高階面試題)

前端開發技術面試題

JS深入如何在 JS 中“深凍結”對象

1. 如果咱們想要確保對象被深凍結,就必須創建一個遞歸函數來凍結對象類型的每個屬性:

2. 沒有深凍結

let person = { name: "Leonardo", profession: { name: "developer"}};Object.freeze(person);person.profession.name = "doctor";console.log(person); //output { name: Leonardo, profession: { name: doctor } }

3. 深凍結

function deepFreeze(object) { let propNames = Object.getOwnPropertyNames(object);for (let name of propNames) { let value = object[name]; object[name] = value && typeof value === "object" ? deepFreeze(value) : value;}return Object.freeze(object);}let person = { name: "Leonardo", profession: { name: "developer"}};deepFreeze(person);person.profession.name = "doctor"; // TypeError: Cannot assign to read only property

手寫call()

/*自定義函數對象的call方法*/export function call (fn, obj, ...args) { // 如果傳入的是null/undefined, this指定為windowif (obj===null || obj===undefined) { obj = obj || window} // 給obj添加一個方法: 屬性名任意, 屬性值必須當前調用call的函數對象 obj.tempFn = fn // 通過obj調用這個方法 const result = obj.tempFn(...args) // 刪除新添加的方法 delete obj.tempFn // 返回函數調用的結果return result}5.3. 手寫apply()/*自定義函數對象的apply方法*/export function apply (fn, obj, args) { // 如果傳入的是null/undefined, this指定為windowif (obj===null || obj===undefined) { obj = obj || window} // 給obj添加一個方法: 屬性名任意, 屬性值必須當前調用call的函數對象 obj.tempFn = fn // 通過obj調用這個方法 const result = obj.tempFn(...args) // 刪除新添加的方法 delete obj.tempFn // 返回函數調用的結果return result}

手寫bind()

import {call} from ./call/* 自定義函數對象的bind方法 重要技術: 高階函數 閉包 call() 三點運算符*/export function bind (fn, obj, ...args) {if (obj===null || obj===undefined) { obj = obj || window}return function (...args2) {call(fn, obj, ...args, ...args2)}}5.5. 手寫一個防抖函數/*實現函數防抖的函數*/export function debounce(callback, delay) {return function () { // console.log(debounce 事件...) // 保存this和arguments const that = this const args = arguments // 清除待執行的定時器任務if (callback.timeoutId) {clearTimeout(callback.timeoutId)} // 每隔delay的時間, 啟動一個新的延遲定時器, 去準備調用callback callback.timeoutId = setTimeout(function () { callback.apply(that, args) // 如果定時器回調執行了, 刪除標記 delete callback.timeoutId}, delay)}}

手寫一個節流函數

/*實現函數節流的函數*/export function throttle(callback, delay) { let start = 0 // 必須保存第一次點擊立即調用return function () { // 它的this是誰就得讓callback()中的this是誰, 它接收的所有實參都直接交給callback() console.log(throttle 事件) const current = Date.now()if (current - start > delay) { // 從第2次點擊開始, 需要間隔時間超過delay callback.apply(this, arguments) start = current}}}

手寫一個深拷貝函數

/*1). 大眾乞丐版 問題1: 函數屬性會丟失 問題2: 循環引用會出錯*/export function deepClone1(target) {return JSON.parse(JSON.stringify(target))}/*獲取數據的類型字符串名*/function getType(data) {return Object.prototype.toString.call(data).slice(8, -1)}/*2). 面試基礎版本 解決問題1: 函數屬性還沒丟失*/export function deepClone2(target) { const type = getType(target)if (type===Object || type===Array) { const cloneTarget = type === Array ? [] : {}for (const key in target) {if (target.hasOwnProperty(key)) { cloneTarget[key] = deepClone2(target[key])}}return cloneTarget} else {return target}}/*3). 面試加強版本 解決問題2: 循環引用正常*/export function deepClone3(target, map = new Map()) { const type = getType(target)if (type===Object || type===Array) { let cloneTarget = map.get(target)if (cloneTarget) {return cloneTarget} cloneTarget = type===Array ? [] : {} map.set(target, cloneTarget)for (const key in target) {if (target.hasOwnProperty(key)) { cloneTarget[key] = deepClone3(target[key], map)}}return cloneTarget} else {return target}}/*4). 面試加強版本2(優化遍歷性能) 數組: while | for | forEach() 優于 for-in | keys()&forEach() 對象: for-in 與 keys()&forEach() 差不多*/export function deepClone4(target, map = new Map()) { const type = getType(target)if (type===Object || type===Array) { let cloneTarget = map.get(target)if (cloneTarget) {return cloneTarget}if (type===Array) { cloneTarget = [] map.set(target, cloneTarget) target.forEach((item, index) => { cloneTarget[index] = deepClone4(item, map)})} else { cloneTarget = {} map.set(target, cloneTarget) Object.keys(target).forEach(key => { cloneTarget[key] = deepClone4(target[key], map)})}return cloneTarget} else {return target}}

自定義instanceof工具函數

/*自定義instanceof工具函數: 語法: myInstanceOf(obj, Type) 功能: 判斷obj是否是Type類型的實例 實現: Type的原型對象是否是obj的原型鏈上的某個對象, 如果是返回true, 否則返回false*/export function myInstanceOf(obj, Type) { // 得到原型對象 let protoObj = obj.__proto__ // 只要原型對象存在while(protoObj) { // 如果原型對象是Type的原型對象, 返回trueif (protoObj === Type.prototype) {return true} // 指定原型對象的原型對象 protoObj = protoObj.__proto__}return false}

自定義new工具函數

/*自定義new工具函數 語法: newInstance(Fn, ...args) 功能: 創建Fn構造函數的實例對象 實現: 創建空對象obj, 調用Fn指定this為obj, 返回obj*/export function newInstance(Fn, ...args) { // 創建一個新的對象 const obj = {} // 執行構造函數 const result = Fn.apply(obj, args) // 相當于: obj.Fn() // 如果構造函數執行的結果是對象, 返回這個對象if (result instanceof Object) {return result} // 如果不是, 返回新創建的對象 obj.__proto__.constructor = Fn // 讓原型對象的構造器屬性指向Fnreturn obj}

手寫axios函數

/* 1. 函數的返回值為promise, 成功的結果為response, 失敗的結果為error 2. 能處理多種類型的請求: GET/POST/PUT/DELETE 3. 函數的參數為一個配置對象 { url: , // 請求地址 method: , // 請求方式GET/POST/PUT/DELETE params: {}, // GET/DELETE請求的query參數 data: {}, // POST或DELETE請求的請求體參數 } 4. 響應json數據自動解析為js的對象/數組*//* 發送任意類型請求的函數 */function axios({ url, method=GET, params={}, data={}}) { // 返回一個Promise對象return new Promise((resolve, reject) => { // 處理method(轉大寫) method = method.toUpperCase() // 處理query參數(拼接到url上) id=1&xxx=abc/* { id: 1, xxx: abc } */ let queryString = Object.keys(params).forEach(key => { queryString = `${key}=${params[key]}&`})if (queryString) { // id=1&xxx=abc& // 去除最后的& queryString = queryString.substring(0, queryString.length-1) // 接到url url = ? queryString} // 1. 執行異步ajax請求 // 創建xhr對象 const request = new XMLHttpRequest() // 打開連接(初始化請求, 沒有請求) request.open(method, url, true) // 發送請求if (method===GET) { request.send()} else if (method===POST || method===PUT || method===DELETE){ request.setRequestHeader(Content-Type, application/json;charset=utf-8) // 告訴服務器請求體的格式是json request.send(JSON.stringify(data)) // 發送json格式請求體參數} // 綁定狀態改變的監聽 request.onreadystatechange = function () { // 如果請求沒有完成, 直接結束if (request.readyState!==4) {return} // 如果響應狀態碼在[200, 300)之間代表成功, 否則失敗 const {status, statusText} = request // 2.1. 如果請求成功了, 調用resolve()if (status>=200 && status<=299) { // 準備結果數據對象response const response = { data: JSON.parse(request.response), status, statusText}resolve(response)} else { // 2.2. 如果請求失敗了, 調用reject()reject(new Error(request error status is status))}}})}/* 發送特定請求的靜態方法 */axios.get = function (url, options) {return axios(Object.assign(options, {url, method: GET}))}axios.delete = function (url, options) {return axios(Object.assign(options, {url, method: DELETE}))}axios.post = function (url, data, options) {return axios(Object.assign(options, {url, data, method: POST}))}axios.put = function (url, data, options) {return axios(Object.assign(options, {url, data, method: PUT}))}export default axios

自定義事件總線

/** 自定義事件總線*/const eventBus = {}/*{ add: [callback1, callback2] delete: [callback3]}*/let callbacksObj = {}/*綁定事件監聽*/eventBus.on = function (eventName, callback) { const callbacks = callbacksObj[eventName]if (callbacks) { callbacks.push(callback)} else { callbacksObj[eventName] = [callback]}}/*分發事件*/eventBus.emit = function (eventName, data) { const callbacks = callbacksObj[eventName]if (callbacks && callbacks.length > 0) { callbacks.forEach(callback => {callback(data)})}}/*移除事件監聽*/eventBus.off = function (eventName) {if (eventName) { delete callbacksObj[eventName]} else { callbacksObj = {}}}export default eventBus

自定義消息訂閱與發布

/*自定義消息訂閱與發布*/const PubSub = {}/* { add: { token1: callback1, token2: callback2 }, update: { token3: callback3 } }*/let callbacksObj = {} // 保存所有回調的容器let id = 0 // 用于生成token的標記// 1. 訂閱消息PubSub.subscribe = function (msgName, callback) { // 確定token const token = token_ id // 取出當前消息對應的callbacks const callbacks = callbacksObj[msgName]if (!callbacks) { callbacksObj[msgName] = {[token]: callback}} else { callbacks[token] = callback} // 返回tokenreturn token}// 2. 發布異步的消息PubSub.publish = function (msgName, data) { // 取出當前消息對應的callbacks let callbacks = callbacksObj[msgName] // 如果有值if (callbacks) { // callbacks = Object.assign({}, callbacks) // 啟動定時器, 異步執行所有的回調函數setTimeout(() => { Object.values(callbacks).forEach(callback => {callback(data)})}, 0)}}// 3. 發布同步的消息PubSub.publishSync = function (msgName, data) { // 取出當前消息對應的callbacks const callbacks = callbacksObj[msgName] // 如果有值if (callbacks) { // 立即同步執行所有的回調函數 Object.values(callbacks).forEach(callback => {callback(data)})}}/*4. 取消消息訂閱 1). 沒有傳值, flag為undefined 2). 傳入token字符串 3). msgName字符串*/PubSub.unsubscribe = function (flag) { // 如果flag沒有指定或者為null, 取消所有if (flag === undefined) { callbacksObj = {}} else if (typeof flag === string) {if (flag.indexOf(token_) === 0) { // flag是token // 找到flag對應的callbacks const callbacks = Object.values(callbacksObj).find(callbacks => callbacks.hasOwnProperty(flag)) // 如果存在, 刪除對應的屬性if (callbacks) { delete callbacks[flag]}} else { // flag是msgName delete callbacksObj[flag]}} else { throw new Error(如果傳入參數, 必須是字符串類型)}}export default PubSub

自定義數組聲明式系列方法

/*實現數組聲明式處理系列工具函數*//*實現map()*/export function map (array, callback) { const arr = []for (let index = 0; index < array.length; index ) { arr.push(callback(array[index], index))}return arr}/*實現reduce()*/export function reduce (array, callback, initValue) { let result = initValuefor (let index = 0; index < array.length; index ) { // 調用回調函數將返回的結果賦值給result result = callback(result, array[index], index)}return result}/*實現filter()*/export function filter(array, callback) { const arr = []for (let index = 0; index < array.length; index ) {if (callback(array[index], index)) { arr.push(array[index])}}return arr}/*實現find()*/export function find (array, callback) {for (let index = 0; index < array.length; index ) {if (callback(array[index], index)) {return array[index]}}return undefined}/*實現findIndex()*/export function findIndex (array, callback) {for (let index = 0; index < array.length; index ) {if (callback(array[index], index)) {return index}}return -1}/* 實現every() */ export function every (array, callback) {for (let index = 0; index < array.length; index ) {if (!callback(array[index], index)) { // 只有一個結果為false, 直接返回falsereturn false}}return true}/*實現some()*/export function some (array, callback) {for (let index = 0; index < array.length; index ) {if (callback(array[index], index)) { // 只有一個結果為true, 直接返回truereturn true}}return false}export function test() { console.log(test()222)}

手寫Promise

const PENDING = pending // 初始未確定的狀態const RESOLVED = resolved // 成功的狀態const REJECTED = rejected // 失敗的狀態/*Promise構造函數*/function Promise(excutor) { const self = this // Promise的實例對象 self.status = PENDING // 狀態屬性, 初始值為pending, 代表初始未確定的狀態 self.data = undefined // 用來存儲結果數據的屬性, 初始值為undefined self.callbacks = [] // {onResolved(){}, onRejected(){}}/* 將promise的狀態改為成功, 指定成功的value */function resolve(value) { // 如果當前不是pending, 直接結束if (self.status !== PENDING) return self.status = RESOLVED // 將狀態改為成功 self.data = value // 保存成功的value // 異步調用所有緩存的待執行成功的回調函數if (self.callbacks.length > 0) { // 啟動一個延遲時間為0的定時器, 在定時器的回調中執行所有成功的回調setTimeout(() => { self.callbacks.forEach(cbsObj => { cbsObj.onResolved(value)})})}}/* 將promise的狀態改為失敗, 指定失敗的reason */function reject(reason) { // 如果當前不是pending, 直接結束if (self.status !== PENDING) return self.status = REJECTED // 將狀態改為失敗 self.data = reason // 保存reason數據 // 異步調用所有緩存的待執行失敗的回調函數if (self.callbacks.length > 0) { // 啟動一個延遲時間為0的定時器, 在定時器的回調中執行所有失敗的回調setTimeout(() => { self.callbacks.forEach(cbsObj => { cbsObj.onRejected(reason)})})}} // 調用excutor來啟動異步任務try {excutor(resolve, reject)} catch (error) { // 執行器執行出錯, 當前promise變為失敗 console.log(-----)reject(error)}}/*用來指定成功/失敗回調函數的方法 1). 如果當前promise是resolved, 異步執行成功的回調函數onResolved 2). 如果當前promise是rejected, 異步執行成功的回調函數onRejected 3). 如果當前promise是pending, 保存回調函數返回一個新的promise對象 它的結果狀態由onResolved或者onRejected執行的結果決定 2.1). 拋出error ==> 變為rejected, 結果值為error 2.2). 返回值不是promise ==> 變為resolved, 結果值為返回值 2.3). 返回值是promise ===> 由這個promise的決定新的promise的結果(成功/失敗)*/Promise.prototype.then = function (onResolved, onRejected) { const self = this onResolved = typeof onResolved === function ? onResolved : value => value // 將value向下傳遞 onRejected = typeof onRejected === function ? onRejected : reason => { throw reason} // 將reason向下傳遞return new Promise((resolve, reject) => { // 什么時候改變它的狀態/* 1. 調用指定的回調函數 2. 根據回調執行結果來更新返回promise的狀態 */function handle(callback) {try { const result = callback(self.data)if (!(result instanceof Promise)) { // 2.2). 返回值不是promise ==> 變為resolved, 結果值為返回值resolve(result)} else { // 2.3). 返回值是promise ===> 由這個promise的決定新的promise的結果(成功/失敗) result.then( value => resolve(value), reason => reject(reason)) // result.then(resolve, reject)}} catch (error) { // 2.1). 拋出error ==> 變為rejected, 結果值為errorreject(error)}}if (self.status === RESOLVED) {setTimeout(() => {handle(onResolved)})} else if (self.status === REJECTED) {setTimeout(() => {handle(onRejected)})} else { // PENDING self.callbacks.push({onResolved(value) {handle(onResolved)},onRejected(reason) {handle(onRejected)}})}})}/*用來指定失敗回調函數的方法catch是then的語法糖*/Promise.prototype.catch = function (onRejected) {return this.then(undefined, onRejected)}/*用來返回一個指定vlaue的成功的promisevalue可能是一個一般的值, 也可能是promise對象*/Promise.resolve = function (value) {return new Promise((resolve, reject) => { // 如果value是一個promise, 最終返回的promise的結果由value決定if (value instanceof Promise) { value.then(resolve, reject)} else { // value不是promise, 返回的是成功的promise, 成功的值就是valueresolve(value)}})}/*用來返回一個指定reason的失敗的promise*/Promise.reject = function (reason) {return new Promise((resolve, reject) => {reject(reason)})}/*返回一個promise, 只有當數組中所有promise都成功才成功, 否則失敗*/Promise.all = function (promises) {return new Promise((resolve, reject) => { let resolvedCount = 0 // 已經成功的數量 const values = new Array(promises.length) // 用來保存成功promise的value值 // 遍歷所有promise, 取其對應的結果 promises.forEach((p, index) => { p.then( value => { resolvedCount values[index] = valueif (resolvedCount === promises.length) { // 都成功了resolve(values)}}, reason => reject(reason))})})}/*返回一個promise, 由第一個完成promise決定*/Promise.race = function (promises) {return new Promise((resolve, reject) => { // 遍歷所有promise, 取其對應的結果 promises.forEach(p => { // 返回的promise由第一個完成p來決定其結果 p.then(resolve, reject)})})}/*返回一個延遲指定時間才成功(也可能失敗)的promise*/Promise.resolveDelay = function (value, time) {return new Promise((resolve, reject) => {setTimeout(() => { // 如果value是一個promise, 最終返回的promise的結果由value決定if (value instanceof Promise) { value.then(resolve, reject)} else { // value不是promise, 返回的是成功的promise, 成功的值就是valueresolve(value)}}, time)})}/*返回一個延遲指定時間才失敗的promise*/Promise.rejectDelay = function (reason, time) {return new Promise((resolve, reject) => {setTimeout(() => {reject(reason)}, time)})}export default Promise

自定義數組扁平化

/*數組扁平化: 取出嵌套數組(多維)中的所有元素放到一個新數組(一維)中 如: [1, [3, [2, 4]]] ==> [1, 3, 2, 4]*//*方法一: 遞歸 reduce() concat()*/export function flatten1 (array) {return array.reduce((pre, item) => {if (Array.isArray(item)) {return pre.concat(flatten1(item))} else {return pre.concat(item)}}, [])}/*方法二: ... some() concat()*/export function flatten2 (array) { let arr = [].concat(...array)while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr)}return arr}

歡迎分享轉載→http://www.avcorse.com/read-226520.html

Copyright ? 2024 有趣生活 All Rights Reserve吉ICP備19000289號-5 TXT地圖HTML地圖XML地圖