JS面試題-那些你不知道的事

Q1:
let s = “1+2+3 * (4 + 5 * (6 + 7))”,寫一個程序,解析這個表達式得到結果(一般化)。
A:
將這個表達式轉換爲“波蘭式”表達式,然後使用棧結構來運算。
Q2:
監測一個對象是否具有某個屬性
A:
hasOwnProperty方法解決
Q3:
創建純函數的緩存
A:

/**
*創建純函數的緩存(閉包解決)
*/
function cached(fn){
	const cache = Object.create(null);
	return function cachedFn(str){
		//第二次進來,如果str之前賦過值,就會從緩存中去取,不用再去調函數操作
		const hit = cache[str];
		return hit || (cache[str] = fn(str));
	}
}
/**
*匹配單詞中的大寫字母,在其前面加上-,如aaA =>aa-A
*\B正則表示匹配了一個位置,這個位置表示不爲單詞邊界的位置,不考慮單詞開頭第一個字母
*/
const hyphenateRE = /\B([A-Z])/g
const hyphenate = cached((str) => {
  return str.replace(hyphenateRE, '-$1').toLowerCase()
})
console.log(hyphenate("aaAA"))//aa-a-a
console.log(hyphenate("aaAA"))//aa-a-a
console.log(hyphenate("AaAA"))//aa-a-a

Q4:
比較兩個對象是否外形相同,鬆散相等
A:

/**
*比較兩個對象外形是否相同
*/	
function isObject(obj){
	return obj !== null && typeof obj === 'object'
}	
//判斷對象是否爲函數
function isFunction(fn) {
   return Object.prototype.toString.call(fn)=== '[object Function]';
}
function looseEqual(a,b){
	//三個等號比較地址,相等則表示同一個對象直接返回true
	if(a===b) return true
	const isObjectA = isObject(a)
	const isObjectB = isObject(b)
	if(isObjectA && isObjectB){//兩個都是對象
		try{
			const isArrayA = Array.isArray(a)
			const isArrayB = Array.isArray(b)
			if(isArrayA && isArrayB){
				return a.length === b.length && a.every((e,i) => {
					//比較每一項是否相同,遞歸調用
					return looseEqual(e,b[i])
				})
			}else if(a instanceof Date && b instanceof Date){
				//日期直接比較時間戳
				return a.getTime() === b.getTime()
			}else if(eval(a) instanceof RegExp && eval(b) instanceof RegExp){
				//正則轉爲時間戳去比較
				return String(a) === String(b)
			}else if(!isObjectA&&!isArrayB){
				const keysA = Object.keys(a)
				const keysB = Object.keys(b)
				return keysA.length === keysB.length && keysA.every(key=>{
					//檢測b包含a嗎
					return looseEqual(a[key],b[key])
				})
			}else{
				return false
			}
		}catch(e){
			return false
		}
	}else if(!isObjectA && !isObjectB){//兩個都不是對象
		return String(a) === String(b)
	}else{
		return false
	}
}

Q5:
確保一個函數只調用一次
A:

/**
*確保一個函數只執行一次
*/
function once(fn){
	let called = false
	return function(){
		if(!called){
			//修改狀態
			called = true
			//綁定上下文
			fn.apply(this,arguments)
		}
	}
}

Q6:
將a=b&c=d&e=f轉換成{a:“b”,c:“d”,e:“f”}的形式
A:

let params = 'a=b&c=d&e=f';
let t = null;
params.split( '&' ).reduce( ( res, v ) => ( t = v.split( '=' ), res[ t[ 0 ] ] = t[ 1 ], res ), {} );

Q7:
數組去重
A:

let arr = [1,2,1,2,3,4,5,3];
let _newArr = [];
方法一:循環遍歷判斷
arr.forEach(v=> _newArr.indexOf(v) === -1&&_newArr.push(v));//indexOf內部隱含着循環,所以進行了兩層循環
方法二:集合處理
let _set = {};
arr.forEach(v=> _set[v] || (_set[v] = true, _newArr.push(v)));//只進行了一層循環
方法三:es6 Set
_newArr = Array.form(new Set(arr))

Q8:
在不使用JSON.stringify()的情況下,如何將JSON轉化爲字符串
A:
採用分而治之的方法,分別對基本類型、數組、對象做處理

/*
 *不使用JSON.stringify將Json對象轉化爲string
 *採用分而治之的方法,針對不同類型分別去處理,將其轉化爲字符串
 */
//檢測是否爲基本數據類型
function isPrimaryType(value){
	let type = typeof value;
	return type === "number" || type === "string" || type === "boolean";
}
//檢測是否爲函數
function isFunction(value){
	return typeof value === "function";
}
//檢測是否爲對象
function isObject(value){
	return typeof value === "object";
}
//返回各自的類型,用於進行二次遞歸處理
function gettype(value){
	if(isPrimaryType(value)){
		return typeof value;
	}
	if(isFunction(value)){
		return "Function";
	}
	if(value.type && typeof value.type === "function"){
		return value.type();
	}
	//使用Object.prototype上的原生toString()方法判斷數據類型
	//[object Object],截取後半部分
	return Object.prototype.toString.call(value).slice(8).slice(0,-1);
}
//處理基本數據類型
class ToJSONString extends String {
	//返回布爾對象的初始值
	toString(){
		return `"${this.valueOf()}"`;
	}
}
function createToJSONString(target){
	return new ToJSONString(target);
}
//處理對象
class ToJSONObject extends Object {
	type(){
		return "ToJSONObject";
	}
	toString(){
		let ret = [];
		//獲取所有的屬性
		let keys = Object.keys(this);
		for(let i = 0, len = keys.length; i < len; i++){
			ret.push(`"${keys[i]}":${this[keys[i]]}`)
		}
		//將數組轉化爲字符串,用逗號隔開
		return `{${ret.join(',')}}`
	}
}
class ToJSONArray extends Array {
	type(){
		return "ToJSONArray";
	}
	toString(){
		return `[${this.join(',')}]`;
	}
}
/**
 * 這裏只考慮基本類型, 數組, Object 類型
 * @param {any} target 數據
*/
function create(target){
	if(isPrimaryType(target)){
		return [gettype(target)==="string"?createToJSONString(target):target,true];
	}
	if(gettype(target)==="Object"){
		return [new ToJSONObject(),false];
	}
	if(gettype(target)==="Array"){
		return [new ToJSONArray(),false];
	}
	return [null,true];
}
function trace(target){
	let [o,isPrimary] = create(target);
	//處理對象和數組
	if(!isPrimary){
		let t = gettype(o);
		switch(t){
			case "ToJSONObject":{
				let keys = Object.keys(target);
				for(let i = 0, len = keys.length; i < len; i++){
					//遞歸調用
					o[keys[i]] = trace(target[keys[i]]);
				}
			} break;
			case "ToJSONArray":{
				for(let i = 0, len = target.length; i < len; i++){
					o[i] = trace(target[i]);
				}
			} break;
		}
	}
	return o;
}

function toJSON(target){
	return trace(target).toString();
}

let obj = {
 name: "star",
 arr: [ 1, 2, 3, "4", '5' ],
 test1: 1,
 test2: true,
 test: {
   name: 'jim',
   age: 19,
   gender: true
 }
};

let res = toJSON( obj );
console.log( res )
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章