大家好,咱们是高灯科技买卖合规前端团队(GFE), 隶归于高灯科技(北京)买卖合规事务作业线研发部,是一个赋有激情、充满创造力、坚持技能驱动全面成长的团队。在金 9 还剩最后的几天银 10 马上就到来的日子里,假如你正在经历作业调整,那么建议你一定要收藏起来,这是一份防备互联网隆冬的必备攻略~

1.输出的成果是什么? 怎样改动循环1输出成果变成循环2的打印成果

for(var i = 0;i<5;i++){
  setTimeout(()=>{
    console.log(i) //五次5
  },1000)
  console.log(i) //0 1 2 3 4
}
for(let i = 0;i<5;i++){
  setTimeout(()=>{
    console.log(i) // 0 1 2 3 4
  },1000)
}
// 改动
for(var i = 0;i<5;i++){
  (function(j) {
      setTimeout( function timer() {
          console.log( j );
      }, j*1000 );
  })(i);
}

这是由于setTimeout是异步履行,每一次for循环的时分,setTimeout都履行一次,可是里面的函数没有被履行,而是被放到了使命行列里,等候履行。只要主线上的使命履行完,才会履行使命行列里的使命。也便是说它会等到for循环悉数运转完毕后,才会履行fun函数,可是当for循环完毕后此刻i的值现已变成了5,因而虽然定时器跑了5秒,操控台上的内容依然是5。

一起由于for循环头部的let不只将i绑定到for循环中,事实上它将其从头绑定到循环体的每一次迭代中,保证上一次迭代完毕的值从头被赋值。setTimeout里面的function()归于一个新的域,经过var界说的变量是无法传入到这个函数履行域中的,经过运用let来声明块变量能作用于这个块,所以function就能运用i这个变量了;这个匿名函数的参数作用域和for参数的作用域不相同,是运用了这一点来完结的。这个匿名函数的作用域有点类似类的特色,是能够被内层办法运用的。

最后呢 运用var声明的变量会存在变量提高的问题,而运用let就不存在变量提高的问题。假如非要运用var作为循环循环头的话,呈现循环后打印出的成果如出一辙的问题,能够运用传参或许闭包的办法

2.数组循环办法有哪些

(1)、forEach:会遍历数组, 没有回来值, 不允许在循环体内写return, 会改动本来数组的内容.forEach()也能够循环方针

(2)、map:遍历数组, 会回来一个新数组, 不会改动本来数组里的内容

(3)、filter:会过滤掉数组中不满意条件的元素, 把满意条件的元素放到一个新数组中, 不改动原数组

(4)、reduce:

let array = [1, 2, 3, 4];
let temp = array.reduce((x, y) => {
	console.log("x,"+x);
	console.log("y,"+y);
	console.log("x+y,",Number(x)+Number(y));
	return x + y;
});
console.log(temp);  // 10
console.log(array);  // [1, 2, 3, 4]

(5)、every:遍历数组, 每一项都是true, 则回来true, 只要有一个是false, 就回来false

(6)、some:遍历数组的每一项, 有一个回来true, 就中止循环

3.script标签中defer和async的差异?

defer:script被异步加载后并不会⽴刻执⾏,而是要等到整个页面在内存中正常烘托完毕后,才会履行。多 个 defer 脚本会依照它们在页面呈现的次序加载。

async:相同是异步加载脚本,差异是脚本加载完毕后⽴即执⾏,这导致async特色下的脚本是乱序的,关于script有先后依靠联系的状况,并不适⽤。

4.用 setTimeout()办法来模拟 setInterval()与 setInterval()之间的什么差异?

首要来看 setInterval 的缺陷,运用 setInterval()创立的定时器保证了定时器代码规则地插 入行列中。这种办法的问题在于,假如定时器代码在代码再次添加到行列之前还没完结履行, 成果就会导致定时器代码接连运转好几次,而之间没有距离。
所以可能会呈现下面的状况:当时履行栈履行的时刻很长,导致事情行列里面积累多个定时器加入的事情,当履行栈完毕后,这些事情会顺次履行而之间没有任何停顿,不能到达距离一段时刻履行的作用。

不过幸运的是:javascript引擎满意聪明,能够防止这个问题。当运用 setInterval()时,仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到行列中。这保证了定时器代码加入行列中最小的时刻距离为指定时刻。这种重复定时器的规则有两个问题:

1.某些距离会被跳过 ;

2.多个定时器的代码履行时刻可能会比预期小 ;

eg: 假定,某个 onclick 事情处理程序运用啦 setInterval()来设置了一个 200ms 的重复定时器。

假如事情处理程序花了 300ms 多一点的时刻完结。

前端 30 问:愿你能三十而立

注:这个比方中的第 1 个定时器是在 205ms 处添加到行列中的,可是直到过了 300ms 处才能够履行。当履行这个定时器代码时,在 405ms 处又给行列添加了别的一个副本。鄙人一个距离,即 605ms 处,第一个定时器代码仍在运转,一起在行列中现已有了一个定时器代码的实例。成果是,在这个时刻点上的定时器代码不会被添加到行列中。成果在 5ms 处添加的定时器代码完毕之后,405ms 处添加的定时器代码就马上履行

所以假如用setTimeout代替的话,就能够保证只要一个事情完毕了之后,才会触发下一个定时器事情。这保证了定时器代码加入到行列中的最小时刻距离为指定距离。

以下是完成的2种简略办法:

function say(){
  //something 
  setTimeout(say,200); 
}
setTimeout(say,200) 
// 或许
setTimeout(function(){ 
  //do something 
  setTimeout(arguments.callee,200); 
},200); 

5.JS 怎样操控一次加载一张图片,加载完后再加载下一张

(1)办法 1

<script type="text/javascript">
  var obj=new Image(); 
	obj.src="https://www.6hu.cc/files/2022/10/1665256428-b7c1217035ab101.jpg"; 
	obj.onload=function(){ 
  	alert('图片的宽度为:'+obj.width+';图片的高度为:'+obj.height); 
  	document.getElementById("mypic").innnerHTML="<img src='"+this.src+"' />"; 
	}
</script> 
<div id="mypic">onloading……</div> 

(2)办法 2

<script type="text/javascript">
  var obj=new Image(); 
	obj.src="https://www.6hu.cc/files/2022/10/1665256428-b7c1217035ab101.jpg"; 
	obj.onreadystatechange=function(){ 
  if(this.readyState=="complete"){ 
    alert('图片的宽度为:'+obj.width+';图片的高度为:'+obj.height); 
    document.getElementById("mypic").innnerHTML="<img src='"+this.src+"' />"; 
    }
  }
</script> 
  <div id="mypic">onloading……</div> 

6.怎么完成 sleep 的作用(es5 或许 es6)

(1)while 循环的办法

function sleep(ms){
  var start=Date.now(),expire=start+ms; 
  while(Date.now()<expire); 
  console.log('1111'); 
  return; 
}

履行 sleep(1000)之后,休眠了 1000ms 之后输出了 1111。上述循环的办法缺陷很明显,容易造成死循环。

(2)经过 promise 来完成

function sleep(ms){
  var temple=new Promise( 
    (resolve)=>{ 
      console.log(111);
      setTimeout(resolve,ms);
    }); 
  return temple 
}
sleep(500).then(
  function(){
    //console.log(222) 
})

//先输出了 111,推迟 500ms 后输出 222

(3)经过 async 封装

function sleep(ms){
  return new Promise((resolve)=>setTimeout(resolve,ms)); 
}
async function test(){ 
  var temple=await sleep(1000); 
  console.log(1111) 
  return temple 
}
test(); 

//推迟 1000ms 输出了 1111

(4).经过 generate 来完成

function* sleep(ms){
  yield new Promise(function(resolve,reject){ 
    console.log(111); 
    setTimeout(resolve,ms); 
  })
}
sleep(500).next().value.then(
  function(){
    console.log(2222)
}) 

7.完成 JS 中一切方针的深度克隆(包装方针,Date 方针,正则方针)

经过递归能够简略完成方针的深度克隆,可是这种办法不管是 ES6 仍是 ES5 完成,都有 相同的缺陷,便是只能完成特定的 object 的深度仿制(比方数组和函数),不能完成包装方针 Number,String ,Boolean,以及 Date 方针,RegExp 方针的仿制。

(1)前文的办法

function deepClone(obj){
  var newObj= obj instanceof Array?[]:{}; 
  for(var i in obj){ 
    newObj[i] = typeof obj[i] == 'object' ? deepClone(obj[i]):obj[i]; 
  }
  return newObj; 
}

这种办法能够完成一般方针和数组方针的克隆,比方:

var arr=[1,2,3]; 
var newArr=deepClone(arr); 
// newArr->[1,2,3] 
var obj={ 
  x:1, 
  y:2 
}
var newObj=deepClone(obj); 
// newObj={x:1,y:2} 

可是不能完成例如包装方针 Number,String,Boolean,以及正则方针 RegExp 和 Date 方针的

克隆,比方:

//Number 包装方针 
var num=new Number(1); 
typeof num // "object" 
var newNum=deepClone(num); 
//newNum -> {} 空方针 
//String 包装方针 
var str=new String("hello"); 
typeof str //"object" 
var newStr=deepClone(str); 
//newStr-> {0:'h',1:'e',2:'l',3:'l',4:'o'}; 
//Boolean 包装方针 
var bol=new Boolean(true); 
typeof bol //"object" 
var newBol=deepClone(bol); 
// newBol ->{} 空方针  

(2)valueof()函数

一切方针都有 valueOf 办法,valueOf 办法关于:假如存在任意原始值,它就默许将方针转化为标明它的原始值。方针是复合值,而且大多数方针无法真正标明为一个原始值,因而默许的 valueOf()办法简略地回来方针本身,而不是回来一个原始值。数组、函数和正则表达式简略地承继了这个默许办法,调用这些类型的实例的 valueOf()办法仅仅简略回来这个方针本身。

关于原始值或许包装类:

function baseClone(base){
  return base.valueOf(); 
}
//Number 
var num=new Number(1); 
var newNum=baseClone(num); 
//newNum->1 
//String 
var str=new String('hello'); 
var newStr=baseClone(str); 
// newStr->"hello" 
//Boolean 
var bol=new Boolean(true); 
var newBol=baseClone(bol); 
//newBol-> true 

其实关于包装类,完全能够用=号来进行克隆,其实没有深度克隆一说,这儿用 valueOf 完成,语法上比较契合规范。

关于 Date 类型:

由于 valueOf 办法,日期类界说的 valueOf()办法会回来它的一个内部标明:1970 年 1 月 1 日以来的毫秒数.因而咱们能够在 Date 的原型上界说克隆的办法:

Date.prototype.clone=function(){
  return new Date(this.valueOf()); 
}
var date=new Date('2010'); 
var newDate=date.clone(); 
// newDate-> Fri Jan 01 2010 08:00:00 GMT+0800 

关于正则方针 RegExp:

RegExp.prototype.clone = function() {
  var pattern = this.valueOf(); 
  var flags = ''; 
  flags += pattern.global ? 'g' : ''; 
  flags += pattern.ignoreCase ? 'i' : ''; 
  flags += pattern.multiline ? 'm' : ''; 
  return new RegExp(pattern.source, flags); 
};
var reg=new RegExp('/111/'); 
var newReg=reg.clone(); 
//newReg-> //111// 

8.JS 监听方针特色的改动

咱们假定这儿有一个 user 方针,

(1)在 ES5 中能够经过 Object.defineProperty 来完成已有特色的监听

Object.defineProperty(user,'name',{
	setfunction(key,value){}
})
//缺陷:假如 id 不在 user 方针中,则不能监听 id 的改动

(2)在 ES6 中能够经过 Proxy 来完成

var user = new Proxy({},{
	set:function(target,key,value,receiver){}
})
//这样即便有特色在 user 中不存在,经过 user.id 来界说也相同能够这样监听这个特色的改动 

9.Vue3.0 里为什么要用 Proxy API 代替 defineProperty API?

答:呼应式优化。

(1)defineProperty API 的局限性最大原因是它只能针对单例特色做监听。

Vue2.x 中的呼应式完成正是根据 defineProperty 中的 descriptor,对 data 中的特色做了遍历 + 递归,为每个特色设置了 getter、setter。

这也便是为什么 Vue 只能对 data 中预界说过的特色做出呼应的原因,在 Vue 中运用下标的办法直接修正特色的值或许添加一个预先不存在的方针特色是无法做到 setter 监听的,这是 defineProperty 的局限性。

(2)Proxy API 的监听是针对一个方针的,这就完全能够署理一切特色。

Proxy API 监听一个方针,那么对这个方针的一切操作会进入监听操作,然后就完全能够署理一切特色,能够了解成,在方针方针之前架起一层“阻拦”,外界对该方针的拜访,都必须先经过这层阻拦,因而供给了一种机制,能够对外界的拜访进行过滤和改写,这样就带来了很大的功能提高和更优的代码。

(3)呼应式是惰性的

在 Vue.js 2.x 中,关于一个深层特色嵌套的方针,要绑架它内部深层次的改动,就需求递归遍历这个方针,履行 Object.defineProperty 把每一层方针数据都变成呼应式的,这无疑会有很大的功能耗费。

在 Vue.js 3.0 中,运用 Proxy API 并不能监听到方针内部深层次的特色改动,因而它的处理办法是在 getter 中去递归呼应式,这样的长处是真正拜访到的内部特色才会变成呼应式,简略的能够说是按需完成呼应式,减少功能耗费。

10、js 中微观使命、微观使命、循环机制的了解

js 归于单线程,分为同步和异步,js代码是自上向下履行的,在主线程中当即履行的便是同步使命,比方简略的逻辑操作及函数,而异步使命不会立马履行,会挪步放到到异步行列中,比方ajax、promise、事情、计时器等等。

先履行同步,主线程完毕后再依照异步的次序再次履行。

事情循环:同步使命进入主线程,当即履行,履行之后异步使命进入主线程,这样循环。

在事情循环中,每进行一次循环操作称为tick,tick 的使命处理模型是比较杂乱的,里面有两个词:分别是 Macro Task (宏使命)和 Micro Task(微使命)

微观使命和微观使命(先履行微观使命,再履行微观使命)

针对js

微观使命:setTimeOut、setTimeInterval、postMessage

微观使命:Promise.then

要点:Promise 同步 Promise.then 异步

console.log("开端111");
setTimeout(function() {
  console.log("setTimeout111");
}, 0);
Promise.resolve().then(function() {
  console.log("promise111");
}).then(function() {
  console.log("promise222");
});
console.log("开端222");

咱们依照进程来剖析下:

1、遇到同步使命,直接先打印 “开端111”。

2、遇到异步 setTimeout ,先放到行列中等候履行。

3、遇到了 Promise ,放到等候行列中。

4、遇到同步使命,直接打印 “开端222”。

5、同步履行完,回来履行行列中的代码,从上往下履行,发现有微观使命 setTimeout 和微观使命 Promise ,那么先履行微观使命,再履行微观使命。

所以打印的次序为: 开端111 、开端222 、 promise111 、 promise222 、 setTimeout111 。

11. rgb和16进制颜色转化

首要咱们需求知道RGB与十六进制之间的联系,例如咱们最常见的白色RGB标明为rgb(255, 255, 255), 十六进制标明为#FFFFFFF, 咱们能够把十六进制颜色除‘#’外按两位切割成一部分,即FF,FF,FF, 看一下十六进制的FF转为十进制是多少呢?没错,便是255!

了解了十六进制和RGB联系之后,咱们就会发现RGB转十六进制办法就很简略了

将RGB的3个数值分别转为十六进制数,然后拼接,即 rgb(255, 255, 255) => ‘#’ + ‘FF’ + ‘FF’ + ‘FF’。 巧妙运用左移,咱们把十六进制数值部分当成一个整数,即FFFFFF,咱们能够了解为FF0000 + FF00 + FF, 好像咱们上面解释,假如左移是根据十六进制计算的,则能够了解为FF << 4, FF << 2, FF, 而实践上咱们转为二进制则变为 FF << 16,如下:

x * 16^4 = x * 2 ^ 16

了解了原理以后,代码如下:

functionRGBFUN(rgb){
//取出rgb中的数值
letarr=rgb.match(/d+/g);
console.log(arr,'输出rgb转化数值')//['0','255','0']输出rgb转化数值
if(!arr||arr.length!==3){
console.error('rgb数值不合法');
return
}
lethex=(arr[0]<<16|arr[1]<<8|arr[2]).toString(16);
//主动补全第一位
if(hex.length<6){
hex='0'+hex;
}
console.log(`#${hex}`,'输出转化之后的数值')//#0ff00输出转化之后的数值
return`#${hex}`;
}
RGBFUN('rgb(0,255,0)')

12. JavaScript位操作:两个操作数相应的比特位有且只要一个1时,成果为1,否则为0

能够完成简略的加密

constvalue=456;
functionencryption(str){
lets='';
str.split('').map(item=>{
s+=handle(item);
})
returns;
}
functiondecryption(str){
lets='';
str.split('').map(item=>{
s+=handle(item);
})
returns;
}
functionhandle(str){
if(/d/.test(str)){
returnstr^value;
}else{
letcode=str.charCodeAt();
letnewCode=code^value;
returnString.fromCharCode(newCode);
}
}
letinit='JS把握位运算';
letresult=encryption(init);//扄戩亅踘穟加密之后
console.log(result,'加密之后')
letdecodeResult=decryption(result);//JS把握位运算解密之后
console.log(decodeResult,'解密之后')

13.【根据webpack】有哪些Loader?用过哪些?

文件

  • val-loader:将代码作为模块履行,并将其导出为 JS 代码
  • ref-loader:用于手动建立文件之间的依靠联系

JSON

  • cson-loader:加载并转化 CSON 文件

语法转化

  • babel-loader:运用 Babel 加载 ES2015+ 代码并将其转化为 ES5
  • esbuild-loader:加载 ES2015+ 代码并运用 esbuild 转译到 ES6+
  • buble-loader:运用 Bubl 加载 ES2015+ 代码并将其转化为 ES5
  • traceur-loader:运用 Traceur 加载 ES2015+ 代码并将其转化为 ES5
  • ts-loader:像加载 JavaScript 相同加载 TypeScript 2.0+
  • coffee-loader:像加载 JavaScript 相同加载 CoffeeScript
  • fengari-loader:运用 fengari 加载 Lua 代码
  • elm-webpack-loader:像加载 JavaScript 相同加载 Elm

模板

  • html-loader:将 HTML 导出为字符串,需求传入静态资源的引用途径
  • pug-loader:加载 Pug 和 Jade 模板并回来一个函数
  • markdown-loader:将 Markdown 编译为 HTML
  • react-markdown-loader:运用 markdown-parse 解析器将 Markdown 编译为 React 组件
  • posthtml-loader:运用 PostHTML 加载并转化 HTML 文件
  • handlebars-loader:将 Handlebars 文件编译为 HTML
  • markup-inline-loader:将 SVG/MathML 文件内嵌到 HTML 中。在将图标字体或 CSS 动画运用于 SVG 时,此功能非常实用。
  • twig-loader:编译 Twig 模板并回来一个函数
  • remark-loader:经过 remark 加载 markdown,且支撑解析内容中的图片

款式

  • style-loader:将模块导出的内容作为款式并添加到 DOM 中
  • css-loader:加载 CSS 文件并解析 import 的 CSS 文件,终究回来 CSS 代码
  • less-loader:加载并编译 LESS 文件
  • sass-loader:加载并编译 SASS/SCSS 文件
  • postcss-loader:运用 PostCSS 加载并转化 CSS/SSS 文件
  • stylus-loader:加载并编译 Stylus 文件

结构

  • vue-loader:加载并编译 Vue 组件
  • angular2-template-loader:加载并编译 Angular 组件

14.谈谈Js怎么完成承继?

1.原型链承继:将父类的实例作为子类的原型

长处:

  1. 简略,易于完成

  2. 父类新增原型办法、原型特色,子类都能拜访到

缺陷:

  1. 无法完成多承继,由于原型一次只能被一个实例更改

  2. 来自原型方针的一切特色被一切实例同享(上诉比方中的color特色)

  3. 创立子类实例时,无法向父结构函数传参

2.结构函数承继:仿制父类的实例特色给子类

长处:

  1. 解决了原型链承继中子类实例同享父类引用特色的问题

  2. 创立子类实例时,能够向父类传递参数

  3. 能够完成多承继(call多个父类方针)

缺陷:

  1. 实例并不是父类的实例,仅仅子类的实例

  2. 只能承继父类实例的特色和办法,不能承继其原型上的特色和办法

  3. 无法完成函数复用,每个子类都有父类实例函数的副本,影响功能

3.组合承继(经典承继):将原型链和借用结构函数的技能组合到一块。运用原型链完成对原型特色和办法的承继,而经过结构函数来完成对实例特色的承继

长处:

  1. 弥补了结构承继的缺陷,现在既能够承继实例的特色和办法,也能够承继原型的特色和办法

  2. 既是子类的实例,也是父类的实例

  3. 能够向父类传递参数

  4. 函数能够复用

缺陷:

  1. 调用了两次父类结构函数,生成了两份实例

  2. constructor指向问题

4.实例承继:为父类实例添加新特征,作为子类实例回来

长处:

  1. 不限制调用办法,不管是new 子类()仍是子类(),回来的方针具有相同的作用

缺陷:

  1. 实例是父类的实例,不是子类的实例

  2. 不支撑多承继

5.复制承继:对父类实例中的的办法与特色复制给子类的原型

长处:

  1. 支撑多承继

缺陷:

  1. 功率低,功能差,占用内存高(由于需求复制父类特色)

  2. 无法获取父类不可枚举的办法(不可枚举的办法,不能运用for-in拜访到)

6.寄生组合承继:经过寄生办法,砍掉父类的实例特色,防止了组合承继生成两份实例的缺陷

长处:

  1. 比较完美(js完成承继首选办法)

缺陷:

1.完成起来较为杂乱(可经过Object.create简化)

7.es6–Class承继:运用extends标明承继自哪个父类,而且在子类结构函数中必须调用super

长处:

1.语法简略易懂,操作更便利

缺陷:

1.并不是一切的浏览器都支撑class关键字 lass Per

15.终究成果会输出什么?

var length = 10;
function fn(){
    console.log(this.length)
}
var obj = {
    length: 5,
    method: function(fn){
        fn();
        arguments[0]()
    }
}
obj.method(fn,1)			//10  2

解析:

1、fn() :任意函数里假如嵌套了非箭头函数,那这个时分,嵌套函数里的 this 在未指定的状况下,应该指向的是 window 方针,所以这儿履行 fn 会打印 window.length。假如运用 let 声明变量时会形成块级作用于,且不存在变量提高;而 var 存在声明提高。所以是输出成果是10;可是假如是let length = 10;那输出成果便是:0 2。

2、arguments0 :在办法调用(假如某个方针的特色是函数,这个特色就叫办法,调用这个特色,就叫办法调用)中,履行函数体的时分,作为特色拜访主体的方针和数组便是其调用办法内 this 的指向。(通俗的说,调用谁的办法 this 就指向谁)。

这儿 arguments0 是作为 arguments 方针的特色 [0] 来调用 fn 的,所以 fn 中的 this 指向特色拜访主体的方针 arguments。

这儿还有一点要注意,arguments 这个参数,指的是 function 的一切实参,与形参无关。也便是调用函数时,实践传入的参数,fn 与 1 作为一个参数存储在 arguments 方针里,所以 arguments 的长度为2,所以输出 2。

16. 怎么完成CLI创立模板项目?

  1. 叙述完成的基本进程

    1. 终端参数解析
    2. CLI交互搜集创立项目必要参数
    3. 复制模板项目
    4. 重写package.json文件(修正项目名称等)
    5. 创立完结后提示或履行项目的初始化进程
  2. 叙述完成进程的注意事项

    1. package.json中name的命名规范
    2. 同名项目再次被创立需求考虑是否掩盖或中止,掩盖的状况下要考虑已创立的项目是否接入的版别办理
    3. 创立完结后提示或履行项目初始化要根据运用时的包办理器来判别
  3. 内容扩展

    1. 在CLI交互搜集参数能够支撑前史项目模板或第三方模板,经过对应模板的创立办法来完成兼容
    2. CLI创立项目通常要先履行装置CLI的指令,再来运转CLI内置的创立项目指令两步,能够考虑运用命名规约来完成直接履行npm create xxx、yarn create xxx 启动CLI创立项目

17. 怎么完成主动化埋点?

主动化埋点能够运用 Babel + 定制埋点插件在项目编译进程中对函数插桩完成埋点主动化,运用Babel主动化插桩需求关注两点:

  1. 埋点模块判别是否现已导入和怎么导入:

    1. 在 Babel 插件履行中经过遍历代码中的ImportDeclaration来剖析是否包含了指定的埋点模块;
    2. 经过Babel内置@babel/helper-module-imports模块来完成埋点模块导入;
  2. 埋点函数怎么生成并刺进到源函数;

    1. 怎么生成:经过内置APItemplate.statement来生成调用埋点函数的AST;
    2. 怎么刺进:函数的不同形式对应的AST中类型包含了ClassMethodArrowFunctionExpressionFunctionExpressionFunctionDeclaration,在 Babel 遍历它们的时分在对应的节点的body中刺进生成的AST,当遇到没有函数体的函数需求添加函数体并处理回来值;

18. 叙述一下JSON Web Token?

  1. 作业原理:

JWT在服务器认证后生成包含用户信息,时刻时刻,安全信息等内容组成的JSON方针来仅有标明当时用户状态,在这以后的数据交互中持续携带来标明恳求的有效性。

  1. 数据结构:

    JWT是有header,payload和signature三部分经过“.”连接起来的字符串,在JWT字符串中没有换行

    1. header是一个JSON方针,用来描绘一些元数据;
    2. payload的格式要求同header,内容首要官方界说字段+自界说的字段来满意事务场景的需求;
    3. “Header”和“Payload”都没有提到加密一说,仅仅进行的字符的编码,所以在“Header”和“Payload”中咱们不应该放置一些用户相关的触及安全的信息,未防止上述两块的内容被中间商阻拦篡改,所以需求用到“Signature”;
signature = HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)
  1. 运用办法:

规范的运用办法为在HTTP的头部添加key为“Authorization”,value为:“ Bearer ”的一组信息,token的具体存储按实践事务处理。

  1. 注意事项:

    1. JWT默许不加密,但能够自行加密处理。
    2. 选用默许不加密的状况,请勿将涉密数据放入JWT中。
    3. 建议选用HTTPS来防止中间人进犯。

19. JavaScript中toString()和join()的差异?

// 声明两个不同的数组
const fruitList = ['苹果', '香蕉', '百香果']
const objList = [
  {
    name: '张三',
    age: 16
  },
  {
    name: '李斯',
    age: 18    
  }
]
// 经过toString()直接进行转化为字符串
console.log(fruitList.toString()) // '苹果,香蕉,百香果'
console.log(objList.toString()) // '[object Object],[object Object]'
// 经过join()自界说拼接进行转化为字符串
console.log(fruitList.join()) // '苹果,香蕉,百香果'
console.log(fruitList.join(',')) // '苹果,香蕉,百香果'
console.log(fruitList.join('、')) // '苹果、香蕉、百香果'
console.log(fruitList.join('切割')) // '苹果切割香蕉切割百香果'
console.log(objList.join()) // '[object Object],[object Object]'

总结结论:

toString()与join()是将数组中的一切元素放入一个字符串。

当join()函数内部参数为空时,join()等价于toString()。

当join(‘,’)函数内部参数为逗号字符,则标明用逗号切割数组,等价于内部参数为空。

当join(‘、’)函数内部参数为顿号字符,则标明用顿号切割数组。

当join(‘切割’)函数内部参数为字符串时,则标明用‘切割’字符串切割数组。

20. null / undefined 的差异

null值:归于null类型,代表“空值”,代表一个空方针指针;运用typeof运算得到 “object”,所以你能够以为它是一个特殊的方针值。

undefined值:归于undefined类型,当一个声明的变量未初始化赋值时,得到的便是undefined。运用typeof运算得到“undefined”。

21. 循环遍历map()与forEach()的差异?

array.map(function(currentValue, index, arr), thisValue)
const nums = [4, 9, 16, 25]
const emptyList = []
const doubleNums = nums.map(Math.sqrt)
console.log(doubleNums) // [2, 3, 4, 5]
console.log(nums) // [4, 9, 16, 25]
console.log(emptyList.map(Math.sqrt)) // []

界说和用法:

map()办法回来一个新数组,数组中的元素为原始数组元素调用函数处理后的值。

map()办法依照原始数组元素次序顺次处理元素。

map()不会对空数组进行检测。

map()不会改动原始数组。

array.forEach(function(currentValue, index, arr), thisValue)
const nums = [4, 9, 16, 25]
const emptyList = []
const doubleNums = nums.forEach(Math.sqrt)
console.log(doubleNums) // undefined
console.log(emptyList.forEach(Math.sqrt)) // undefined

界说和用法:

forEach()办法用于调用数组的每个元素,并将元素传递给回调函数。

forEach()关于空数组是不会履行回调函数的。

差异:

forEach()办法不会回来履行成果,而是undefined。也便是说,forEach()会修正本来的数组。而map()办法会得到一个新的数组并回来。

map()会分配内存空间存储新数组并回来,forEach()不会回来数据。

forEach()允许callback更改原始数组的元素。map()回来新的数组。

22. for/in 与 for/of有什么差异?

Array.prototype.method = function () {}
let myArray = [1, 2, 3]
myArray.name = '数组';
for (let index in myArray) {
  console.log(index) // 0,1,2, name, method
  console.log(myArray[index]) //1,2,3,数组,f() {}
}
for (let val of myArray) {
  console.log(val) // 1,2,3
}

最直接的差异便是: for/in遍历的是数组的索引,而for/of遍历的是数组元素值

for/in遍历的缺陷:

  1. 索引是字符串类型的数字,所以不能直接进行几何运算
  2. 遍历次序可能不是实践的内部次序
  3. for/in会遍历数组一切的可枚举特色,包含原型。

所以一般用来遍历方针,而不是数组。

for/of遍历的缺陷:

for/of不支撑一般方针,想遍历方针的特色,能够用for/in循环,或许内建的Object.keys()办法:

Object.keys(obj)获取方针的实例特色组成的数组,不包含原型办法和特色

for(let key of Object.keys(obj)) {
  console.log(key + ":" + Object[key])
}

for/of语句创立一个循环来迭代可迭代的方针,允许遍历Arrays,Strings,Map, Set等可迭代的数据结构

// variable 每个迭代的特色值被分配给该变量。
// iterable 一个具有可枚举特色而且能够迭代的方针。
for(let variable of iterable) {
  statement
}

整体来说:for/in遍历方针;for/of遍历数组

23.css 的烘托层组成是什么,浏览器怎么创立新的烘托层

在 DOM 树中每个节点都会对应一个烘托方针(RenderObject),当它们的烘托方针处于相同的坐标空间(z 轴空间)时,就会形成一个 RenderLayers,也便是烘托层。烘托层将保证页面元素以正确的次序堆叠,这时分就会呈现层组成(composite),然后正确处理透明元素和堆叠元素的显示。关于有方位堆叠的元素的页面,这个进程特别重要,由于一旦图层的兼并次序犯错,将会导致元素显示反常。

浏览器怎么创立新的烘托层

  • 根元素 document
  • 有明确的定位特色(relative、fixed、sticky、absolute)
  • opacity < 1
  • 有 CSS fliter 特色
  • 有 CSS mask 特色
  • 有 CSS mix-blend-mode 特色且值不为 normal
  • 有 CSS transform 特色且值不为 none
  • backface-visibility 特色为 hidden
  • 有 CSS reflection 特色
  • 有 CSS column-count 特色且值不为 auto 或许有 CSS column-width 特色且值不为 auto
  • 当时有关于 opacity、transform、fliter、backdrop-filter 运用动画
  • overflow 不为 visible

24.路由原理 history 和 hash 两种路由办法的特色

hash 形式

  1. location.hash 的值实践便是 URL 中#后面的东西 它的特色在于:hash 虽然呈现 URL 中,但不会被包含在 HTTP 恳求中,对后端完全没有影响,因而改动 hash 不会从头加载页面。
  2. 能够为 hash 的改动添加监听事情

window.addEventListener(“hashchange”, funcRef, false);

每一次改动 hash(window.location.hash),都会在浏览器的拜访前史中添加一个记录运用 hash 的以上特色,就能够来完成前端路由“更新视图但不从头恳求页面”的功能了

特色:兼容性好可是不美观

history 形式

运用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 办法。

这两个办法运用于浏览器的前史记录站,在当时已有的 back、forward、go 的根底之上,它们供给了对前史记录进行修正的功能。这两个办法有个共同的特色:当调用他们修正浏览器前史记录栈后,虽然当时 URL 改动了,但浏览器不会改写页面,这就为单页运用前端路由“更新视图但不从头恳求页面”供给了根底。

特色:虽然美观,可是改写会呈现 404 需求后端进行装备

25.XMLHttpRequest与fetch的差异?

(1).XMLHttpRequest 方针在一切现代的浏览器都支撑,Fetch 是一种新的原生 JavaScript API,目前大多数浏览器都支撑

(2).XMLHttpRequest根据onreadystatechange履行回调,Fetch API 运用 Promise,防止了回调。

(3).Fetch只对网络恳求报错,对400,500都作为成功的恳求,需求封装去处理。

(4).Fetch 恳求默许是不带 cookie 的,需求设置 fetch(url, {credentials: ‘include’})。

(5).Fetch不支撑abort,由于Fetch回来的是一个promise,不支撑超时操控,运用setTimeout及Promise.reject的完成的超时操控并不能阻止恳求进程持续在后台运转,造成了量的糟蹋。

(6).fetch() 示例中,能够传递字符串界说 的URL 端点,也能够传递一个可装备的 Request 方针。

(7).在 XMLHttpRequest 中办理缓存很费事,Fetch 方针中内置了对缓存的支撑:

(8).跨域恳求中,Fetch 供给了一个形式特色,能够在参数中设置‘no-cors’特色。

(9).默许状况下,fetch() 和 XMLHttpRequest 都遵从服务器重定向。可是,fetch() 在参数中供给了可选项:

redirect

‘follow’ —— 遵从一切重定向(默许)

‘error’ —— 产生重定向时中止(拒绝)

‘manual’ —— 回来手动处理的呼应

(10).XMLHttpRequest 将整个呼应读入内存缓冲区,可是 fetch() 能够流式传输恳求和呼应数据,这是一项新技能,流允许你在发送或接收时处理更小的数据块。

(11).Deno 和 Node 中完全支撑 Fetch,XMLHttpRequest 只在客户端被支撑。

26.前端怎么完成大文件下载?

(1).后端服务支撑的状况下能够运用分块下载。

(2).云上文件能够选用a标签办法,经过浏览器默许机制完成下载

(3).借助StreamAPI与Service Worker完成

27.常见几种前端微服务及完成原理

微前端架构将后端微服务的理念运用于浏览器端,即将 Web 运用由单一的单体运用转变为多个小型前端运用聚合为一的运用。

微前端架构一般能够由以下几种办法进行:

  1. 路由分发

经过路由将不同的事务分发到不同的、独立前端运用上。其通常能够经过 HTTP 服务器的反向署理来完成,又或许是运用结构自带的路由来解决。

  1. 经过iframe容器

运用iframe创立一个全新的独立的宿主环境,运转各自独立的前端运用

  1. 前端微服务化

在页面适宜的当地引进或许创立 DOM,用户拜访到对应URL时,加载对应的运用,并能卸载运用

  1. 运用微件化

也叫组合式集成,即经过软件工程的办法在构建前、构建时、构建后等进程中,对运用进行一步的拆分,并从头组合

  1. 根据Web Components

运用 Web Components 技能构建独立于结构的组件,随后在对应的结构中引进这些组件

28.前端布置都有哪些计划?

前端布置的办法大致有三种,

  • 运用Nginx,Tomcat,IIS等web服务器布置
  • Dokcer布置
  • OSS+CDN 布置,或COS

29.常见发布计划有几种

  1. 蓝绿发布

蓝绿发布是指发布进程中新运用发布测试经过后,经过切换网关流量, 一键升级运用的发布办法

  1. 滚动发布

一般是中止一个或多个服务,履行更新,并从头将其投入运用,周而复始,直到微服务中一切的因公都更新成新版别。

  1. 灰度发布

是指在黑与白之间,能够滑润过渡的一种发布办法。AB test便是一种灰度发布办法,让一部分用户持续用A,一部分用户开端用B,假如用户对B没有什么反对意见,那么逐步扩大范围,把一切用户都迁移到B上面来。灰度发布能够保证整体体系的稳定,在初始灰度的时分就能够发现、调整问题,以保证其影响度,而咱们平常所说的金丝雀布置也便是灰度发布的一种办法。

30.怎么设计一套A/B计划

A/B发布是一种比较高档的流量分配计划,例如根据 URL 是否匹配恳求不同的版别运用,或许根据 Header 下某个自界说参数进行用户的区分,然后恳求不同的版别运用

触及流量办理策略,Istio ,docker,k8s等技能

当时微服务、云原生的理念逐步深化,现有前端的开发办法和前端架构也将跟随着不断改动,运用好以上技能能够完成更迅速地扩展,更稳定地交给,运用之间的联系也会愈加紧密,未来几年的前端也必将是微服务化的年代。

结语:

看到这儿不知道你有没有得到收成呢?假如你还有更多的抗冻攻略欢迎你在评论区留言,共享给更多的JY,假如上面的内容你还要问题也能够留言交流,愿每一次的互联网隆冬都打不倒任何一个有准备的JY~