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 )
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值