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)