下载APP

小红书面试题

1.字符串反转

let str = "hello world";
let newStr = str.split("").reverse().join("");
console.log(newStr);

2.url解析函数 parse 实现



function parseURL(url) {
	var a = document.createElement('a');
	a.href = url;
	return {
		source: url,
		protocol: a.protocol.replace(':',''),
		host: a.hostname,
		port: a.port,
		query: a.search,
		params: (function(){
			var ret = {},
			seg = a.search.replace(/^\?/,'').split('&'),
			len = seg.length, i = 0, s;
			for (;i<len;i++) {
				if (!seg[i]) { continue; }
				s = seg[i].split('=');
				ret[s[0]] = s[1];
			}
			return ret;
		})(),
		file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1],
		hash: a.hash.replace('#',''),
		path: a.pathname.replace(/^([^\/])/,'/$1'),
		relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1],
		segments: a.pathname.replace(/^\//,'').split('/')
	};
}

//使用
var myURL = parseURL('http://abc.com:8080/dir/index.html?id=255&m=hello#top');
myURL.file; // = 'index.html'
myURL.hash; // = 'top'
myURL.host; // = 'abc.com'
myURL.query; // = '?id=255&m=hello'
myURL.params; // = Object = { id: 255, m: hello }
myURL.path; // = '/dir/index.html'
myURL.segments; // = Array = ['dir', 'index.html']
myURL.port; // = '8080'
myURL.protocol; // = 'http'
myURL.source; // = 'http://abc.com:8080/dir/index.html?id=255&m=hello#top' 

3.react、angular、vue 区别和应用场景

区别

  • 双向数据绑定
    Angular使用双向数据绑定,React使用单向数据绑定,Vue支持两者,React要想实现双向绑定需要额外实现,比较麻烦

  • 代码结构
    Vue与Angular语言比较像,特别是Vue2.x跟AngularJs,Vue3.x 高度集成Typescrpt以后,跟Angular比较像。因为Vue的想法很多来自于AngularJs。Angular采用MVC分层结构,严格面向对象,页面组件会包含三个文件,组件html,css,ts,而Vue会倾向于把这三个内聚在一个.vue文件里面,所以Angular会多很多文件。

  • 语言支持:
    Angular必须使用Typescript来开发,代码文件都是ts的,Vue2.x版本只是支持ts,但是主要还是javascript,到了Vue3.x 才实现与ts高度支持,变成主要ts文件了,而React 就是一切都是javascript

  • JSX
    JSX是一种JavaScript的语法扩展。在 React 中,使用JSX来描述用户界面,所有的组件的渲染功能都依靠 JSX;Vue也支持JSX语发,但还是页面还是使用Html模板;Angular不支持JSX。对于习惯HTML 的开发者来说,Html模板比起 JSX 读写起来更自然, 对于React方式会不习惯

  • 指令
    Angular与Vue都支持指令,React没有指令概念但通过其它替换

应用场景

  • react适合中大型应用开发,适合大批量数据展示的场景
  • angular适合大型超大型web应用开发
  • vue适合从简单到复杂的前端单页应用,例如单一权限类后台项目

4.proxy 兼容 polyfill实现

Proxy 可以拦截对象的读取、修改遍历等操作,这个 polyfill 只支持 get 和 set。 通过 defineProperty 和 VBScript 实现。 低版本浏览器 Object.defineProperty 用__defineGetter__、__defineSetter__实现。

if(!this.Proxy){
	(function(window){
		var seq=0;
		var dfGetter=function(target, property, receiver){
			return target[property];
		};
		var dfSetter=function(target, property, value,  receiver){
			target[property]=value;
		};
		var afterRevoke=function(){
			throw "illegal operation attempted on a revoked proxy";
		};
		if(Object.defineProperties){
			window.Proxy=function(target, handler){
				var me=this;
				if(!handler.get){
					handler.get=dfGetter;
				}
				if(!handler.set){
					handler.set=dfSetter;
				}
				Object.keys(target).forEach(function(key){
					Object.defineProperty(me,key,{
						enumerable:true,
						get:function(){
							return handler.get(target,key,me);
						},
						set:function(value){
							if(handler.set(target,key,value,me)===false){
								throw new TypeError("'set' on proxy: trap returned falsish for property '"+key+"'");
							}
						}
					});
				});
			};
		}else if(window.execScript){
			//从avalon学到的方式,通过VB
			window.VBProxySetter=function(target, property, value, receiver, handler){
				if(handler.set(target, property, value, receiver)===false){
					throw new TypeError("'set' on proxy: trap returned falsish for property '"+key+"'");
				}
			};
			window.VBProxyGetter=function(target,property, receiver, handler){
				return handler.get(target,property, receiver);
			};
			window.VBProxyPool=new Map();
			window.VBProxyFactory=function(target,handler){
				var className=VBProxyPool.get(target);
				if(!className){
					className="VBClass_"+(seq++);
					VBProxyPool.set(target,className);
					var buffer=["Class "+className];
					buffer.push('Public [__target__]');
					buffer.push('Public [__handler__]');
					Object.keys(target).forEach(function(key){
						if(key.match(/[a-zA-Z0-9_$]/)){
							buffer.push(
								'Public Property Let ['+key+'](var)',
								'	Call VBProxySetter([__target__],"'+key+'",var,Me,[__handler__])',
								'End Property',
								'Public Property Set ['+key+'](var)',
								'	Call VBProxySetter([__target__],"'+key+'",var,Me,[__handler__])',
								'End Property',
								'Public Property Get ['+key+']',
								'	On Error Resume Next', //必须优先使用set语句,否则它会误将数组当字符串返回
								'	Set ['+key+']=VBProxyGetter([__target__],"'+key+'",Me,[__handler__])',
								'	If Err.Number <> 0 Then',
								'		['+key+']=VBProxyGetter([__target__],"'+key+'",Me,[__handler__])',
								'	End If',
								'	On Error Goto 0',
								'End Property');
						}
					});
					buffer.push('End Class');
					buffer.push(
						'Function '+className+'_Factory(target,handler)',
						'	Dim o',
						'	Set o = New '+className,
						'	Set o.[__target__]=target',
						'	Set o.[__handler__]=handler',
						'	Set '+className+'_Factory=o',
						'End Function'
					);
					try{
						window.execScript(buffer.join('\n'), 'VBScript');
					}catch(e){
						alert(buffer.join('\n'));
					}
				}
				return window[className+'_Factory'](target,handler); //得到其产品
			};
			window.Proxy=function(target, handler){
				if(!handler.get){
					handler.get=dfGetter;
				}
				if(!handler.set){
					handler.set=dfSetter;
				}
				var me=VBProxyFactory(target,handler);
				return me;
			};
		}
		Proxy.revocable=function(target,handler){
			var r={};
			r.proxy=new Proxy(target,handler);
			r.revoke=function(){
				handler.get=handler.set=afterRevoke;
			};
			return r;
		};
	})(this);
}

5.Vue 的路由守卫函数

详细解析:https://blog.csdn.net/m0_49515138/article/details/127983043

6.Object.create(obj,propertiesObject)、new Obejct()和{}有什么区别?

创建流程

  • {}创建对象时,不会调用构造函数,js引擎会创建一个空对象,然后改变this指向新创建的对象,
  • new则是需要经历以下步骤
    • 先创建空对象
    • 接着设置原型链,即设置新对象的 constructor 属性为构造函数的名称,设置新对象的__proto__属性指向构造函数的prototype对象
    • 接着使用新对象的调用函数,函数中的 this 被指向新对象,
    • 最后如果无返回值或者返回一个非对象值,则将新对象返回;如果返回值是一个新对象的话那么直接返回该对象。
  • Object.create(obj,propertiesObject)方法支持接受两个参数,obj是一个对象,是必传的,会作为新创建的对象的原型,propertiesObject是可选参数,propertiesObject的属性名称将是新创建的对象的属性名称,propertiesObject属性的值应该是属性描述符,可见Object.create()不会和new和{}一样默认继承 Object原型链的属性和方法,而是将入参指定对象继承到原型链上

{}创建对象的性能比new和 Object.create要好。

创建结果

  • {}是和new所创建出的对象在本质上没有区别,都继承了Object原型链(Obejct.prototype)的属性和方法;
  • Object.create(null)创建的对象没有任何属性和方法
  • Object.create(Object.prototype)则是指定了Object原型链作为新创建对象的原型,效果和new Obejct()和{}就是一样的了

7.微前端

https://blog.csdn.net/huangpb123/article/details/123215785

8.commonjs和AMD的区别

CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。 AMD规范则是非同步加载模块,允许指定回调函数。

由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。

原文链接:https://blog.csdn.net/Leo_DLi/article/details/102533785

9.手写Promise.allSettled


/**
 * 首先了解Promise.allSettled什么作用和用法
 * 相对于 Promise.all 需要所有promise都成功时才 resolve或者有一个失败时进行reject
 * Promise.allSettled则不区分这些promise是resolve还是reject了,只要都执行完毕了,那Promise.allSettled就会返回
 * 返回数据格式如下[{status:"fulfilled", value:result},{status:"rejected", reason:error} ]
 */
function PromiseAllSettled(promiseArr) {
    // 用一个Promise封装,以便于在全部待执行promise执行完后,统一进行结果处理
	return new Promise((resolve, reject) => {
        // 简单的入参校验
		if(!Array.isArray(promiseArr)) {
			reject(new TypeError("arguments must be an array"))
		}
		
		const promiseLen = promiseArr.length;
		const res = [];
        // 记录执行完的Promise数量
		let count = 0;
		for(let i=0; i<promiseLen; i++) {
            //熟悉的Promise.resolve ,这里Promise.resolve()的入参是promiseArr[i],它是个Promise对象
            // Promise.resolve(Promise对象)则会把入参Promise对象原样返回 具体看这里https://www.cnblogs.com/polk6/p/14781550.html
			Promise.resolve(promiseArr[i])
			.then((value) => {
				res[i] = {
					status: 'fulfilled',
					value
				}
			})
			.catch((reason) => {
				res[i] = {
					status: 'rejected',
					reason
				}
			})
			.finally(() => {
                // 利用finally在Promise执行完之后无论resolve还是reject都会执行的特性,做全部Promise执行统计
				count++;
                // 判断执行完了就调用最外层包装的Promise的resolve,进行统一的结果返回
				if(count == promiseLen) {
					resolve(res)
				}
			})
		}
	})
}

10.输入一个 Promise 实例数组,输出最快、最慢的实例,以及每个实例的响应时长

基于上题中Promise.allSettled的代码,统计每个Promise的执行时间,在返回值中返回出来


/**
 * 首先了解Promise.allSettled什么作用和用法
 * 相对于 Promise.all 需要所有promise都成功时才 resolve或者有一个失败时进行reject
 * Promise.allSettled则不区分这些promise是resolve还是reject了,只要都执行完毕了,那Promise.allSettled就会返回
 * 返回数据格式如下[{status:"fulfilled", value:result},{status:"rejected", reason:error} ]
 */
function PromiseAllSettled(promiseArr) {
    // 用一个Promise封装,以便于在全部待执行promise执行完后,统一进行结果处理
    return new Promise((resolve, reject) => {
        // 简单的入参校验
        if (!Array.isArray(promiseArr)) {
            reject(new TypeError("arguments must be an array"))
        }

        const promiseLen = promiseArr.length;
        const res = [];
        // 记录执行完的Promise数量
        let count = 0;
        for (let i = 0; i < promiseLen; i++) {
            //熟悉的Promise.resolve ,这里Promise.resolve()的入参是promiseArr[i],它是个Promise对象
            // Promise.resolve(Promise对象)则会把入参Promise对象原样返回 具体看这里https://www.cnblogs.com/polk6/p/14781550.html
            const startTime = Date.now()
            Promise.resolve(promiseArr[i])
                .then((value) => {
                    res[i] = {
                        status: 'fulfilled',
                        value,
                        //加一个执行时间计算
                        cost: Date.now() - startTime
                    }
                })
                .catch((reason) => {
                    res[i] = {
                        status: 'rejected',
                        reason,
                        //加一个执行时间计算
                        cost: Date.now() - startTime
                    }
                })
                .finally(() => {
                    // 利用finally在Promise执行完之后无论resolve还是reject都会执行的特性,做全部Promise执行统计
                    count++;
                    // 判断执行完了就调用最外层包装的Promise的resolve,进行统一的结果返回
                    if (count == promiseLen) {
                        resolve(res)
                    }
                })
        }
    })
}

11.小程序解决什么问题?

  • 解决“一端开发,多端上架”的研发效率问题
  • 解决内网软件管控问题
  • 解决发版效率问题

12.小程序的view和webview的区别

暂未找到合适的答案

13.前端分包最佳实践

https://www.51cto.com/article/689344.html

14.实现Array.group()


//Array.group就是将原数组,按照数组元素中的某个属性进行分类,
// 例如[{name:'dzc',province:'shandong'},{name:'wx',province:'hebei'},{name:'dzc12',province:'shandong'}]按照province分类,
// 那结果就是 {shandong:[{name:'dzc',province:'shandong'},{name:'dzc12',province:'shandong'}], hebing:[{name:'wx',province:'hebei'}]}
//其实原生的group函数比较复杂,支持的入参也很多,这里我们实现的逻辑

// fn是(element,index,array)=>{}样式的回调函数,它需要返回一个string,这个string就表示当前这个元素属于什么类别
Array.prototype._group = function (fn) {
    const result = {}
    for (let index = 0; index < this.length; index++) {
        const element = this[index];
        //获取当前元素的分类
        const category = fn(element, index, this)
        // 判断这个分类是否存在
        if (result[category]) {
            //分类已存在就push进去
            result[category].push(element)
        } else {
            // 分类不存在就创建一个
            result[category] = [element]  //[element] 将该条数据放进数组
        }
    }
    return result
}

//使用

const orderList = [{
    nickName: 'steven',
    productName: '西瓜',
    price: 29,
    province: 'henan',
  },{
    nickName: '对方的',
    productName: '杨梅',
    price: 22,
    province: 'shanxi',
  },{
    nickName: '范电池',
    productName: '苹果',
    price: 19,
    province: 'dongbei',
  },{
    nickName: '调查v',
    productName: '桃子',
    price: 88,
    province: 'shanxi',
  },{
    nickName: '2号',
    productName: '桃子',
    price: 88,
    province: 'shanxi',
  }]
  
  const group=orderList._group(({province})=>province)
  console.log(group)
  
在线举报