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 )