手写 bind、apply、call

// callFunction.prototype.call = function (context, ...args) {  context = context || window;  const fnSymbol = Symbol("fn");  context[fnSymbol] = this;  context[fnSymbol](...args);  delete context[fnSymbol];}
// applyFunction.prototype.apply = function (context, argsArr) {  context = context || window;  const fnSymbol = Symbol("fn");  context[fnSymbol] = this;  context[fnSymbol](...argsArr);  delete context[fnSymbol];}
// bindFunction.prototype.bind = function (context, ...args) {  context = context || window;  const fnSymbol = Symbol("fn");  context[fnSymbol] = this;  return function (..._args) {    args = args.concat(_args);    context[fnSymbol](...args);    delete context[fnSymbol];     }}

节流

节流(throttle):触发高频事件,且 N 秒内只执行一次。这就好比公交车,10 分钟一趟,10 分钟内有多少人在公交站等我不论,10 分钟一到我就要发车走人!相似qq飞车的复位按钮。

核心思想:应用工夫戳或标记来实现,立刻执行一次,而后每 N 秒执行一次。如果N秒内触发则间接返回。

利用:节流常利用于鼠标一直点击触发、监听滚动事件。

实现:

// 版本一:标记实现function throttle(fn, wait){    let flag = true;  // 设置一个标记    return function(...args){        if(!flag) return;        flag = false;        setTimeout(() => {            fn.call(this, ...args);            flag = true;        }, wait);    }}// 版本二:工夫戳实现function throttle(fn, wait) {    let pre = 0;    return function(...args) {        let now = new Date();        if(now - pre < wait) return;        pre = now;        fn.call(this, ...args);    }}

代码输入问题

function fun(n, o) {  console.log(o)  return {    fun: function(m){      return fun(m, n);    }  };}var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);var b = fun(0).fun(1).fun(2).fun(3);var c = fun(0).fun(1);  c.fun(2);  c.fun(3);

输入后果:

undefined  0  0  0undefined  0  1  2undefined  0  1  1

这是一道对于闭包的题目,对于fun办法,调用之后返回的是一个对象。咱们晓得,当调用函数的时候传入的实参比函数申明时指定的形参个数要少,剩下的形参都将设置为undefined值。所以 console.log(o); 会输入undefined。而a就是是fun(0)返回的那个对象。也就是说,函数fun中参数 n 的值是0,而返回的那个对象中,须要一个参数n,而这个对象的作用域中没有n,它就持续沿着作用域向上一级的作用域中寻找n,最初在函数fun中找到了n,n的值是0。理解了这一点,其余运算就很简略了,以此类推。

说一下JSON.stringify有什么毛病?

1.如果obj外面有工夫对象,则JSON.stringify后再JSON.parse的后果,工夫将只是字符串的模式,而不是对象的模式2.如果obj里有RegExp(正则表达式的缩写)、Error对象,则序列化的后果将只失去空对象;3、如果obj里有函数,undefined,则序列化的后果会把函数或 undefined失落;4、如果obj里有NaN、Infinity和-Infinity,则序列化的后果会变成null5、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则应用JSON.parse(JSON.stringify(obj))深拷贝后,会抛弃对象的constructor;6、如果对象中存在循环援用的状况也无奈正确实现深拷贝;

实现一个宽高自适应的正方形

  • 利用vw来实现:
.square {  width: 10%;  height: 10vw;  background: tomato;}
  • 利用元素的margin/padding百分比是绝对父元素width的性质来实现:
.square {  width: 20%;  height: 0;  padding-top: 20%;  background: orange;}
  • 利用子元素的margin-top的值来实现:
.square {  width: 30%;  overflow: hidden;  background: yellow;}.square::after {  content: '';  display: block;  margin-top: 100%;}

对 rest 参数的了解

扩大运算符被用在函数形参上时,它还能够把一个拆散的参数序列整合成一个数组

function mutiple(...args) {  let result = 1;  for (var val of args) {    result *= val;  }  return result;}mutiple(1, 2, 3, 4) // 24

这里,传入 mutiple 的是四个拆散的参数,然而如果在 mutiple 函数里尝试输入 args 的值,会发现它是一个数组:

function mutiple(...args) {  console.log(args)}mutiple(1, 2, 3, 4) // [1, 2, 3, 4]

这就是 … rest运算符的又一层威力了,它能够把函数的多个入参收敛进一个数组里。这一点常常用于获取函数的多余参数,或者像下面这样解决函数参数个数不确定的状况。

原型

构造函数是一种非凡的办法,次要用来在创建对象时初始化对象。每个构造函数都有prototype(原型)(箭头函数以及Function.prototype.bind()没有)属性,这个prototype(原型)属性是一个指针,指向一个对象,这个对象的用处是蕴含特定类型的所有实例共享的属性和办法,即这个原型对象是用来给实例对象共享属性和办法的。每个实例对象的__proto__都指向这个构造函数/类的prototype属性。面向对象的三大个性:继承/多态/封装对于new操作符:1. new执行的函数, 函数外部默认生成了一个对象2. 函数外部的this默认指向了这个new生成的对象3. new执行函数生成的这个对象, 是函数的默认返回值ES5例子:function Person(obj) {    this.name = obj.name    this.age= obj.age}// 原型办法Person.prototype.say = function() {  console.log('你好,', this.name )}// p为实例化对象,new Person()这个操作称为构造函数的实例化let p = new Person({name: '番茄', age: '27'})console.log(p.name, p.age)p.say()ES6例子:class Person{    constructor(obj) {      this.name = obj.name        this.age= obj.age  }  say() {      console.log(this.name)  }}let p = new Person({name: 'ES6-番茄', age: '27'})console.log(p.name, p.age)p.say()

src和href的区别

src和href都是用来援用内部的资源,它们的区别如下:

  • src: 示意对资源的援用,它指向的内容会嵌入到以后标签所在的地位。src会将其指向的资源下载并应⽤到⽂档内,如申请js脚本。当浏览器解析到该元素时,会暂停其余资源的下载和解决,直到将该资源加载、编译、执⾏结束,所以⼀般js脚本会放在页面底部。
  • href: 示意超文本援用,它指向一些网络资源,建设和以后元素或本文档的链接关系。当浏览器辨认到它他指向的⽂件时,就会并⾏下载资源,不会停⽌对以后⽂档的解决。 罕用在a、link等标签上。

数组去重

第一种: 通过ES6新个性Set()例如: var arr = [1, 2, 3, 1, 2]; var newArr= [...new Set(arr)]
第二种:封装函数利用 {} 和【】function uniqueEasy(arr) {    if(!arr instanceof Array) {        throw Error('以后传入的不是数组')    }    let list = []    let obj = {}    arr.forEach(item => {        if(!obj[item]) {            list.push(item)            obj[item] = true        }    })    return list}

当然还有其余的办法,但自己我的项目中个别应用以上两种根本满足

map和foreach有什么区别

foreach()办法会针对每一个元素执行提供得函数,该办法没有返回值,是否会扭转原数组取决与数组元素的类型是根本类型还是援用类型map()办法不会扭转原数组的值,返回一个新数组,新数组中的值为原数组调用函数解决之后的值:

什么是闭包,闭包的作用是什么

当一个外部函数被调用,就会造成闭包,闭包就是可能读取其余函数外部变量的函数。闭包作用:局部变量无奈共享和短暂的保留,而全局变量可能造成变量净化,所以咱们心愿有一种机制既能够短暂的保留变量又不会造成全局净化。

行内元素有哪些?块级元素有哪些? 空(void)元素有那些?

  • 行内元素有:a b span img input select strong
  • 块级元素有:div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p

空元素,即没有内容的HTML元素。空元素是在开始标签中敞开的,也就是空元素没有闭合标签:

  • 常见的有:<br><hr><img><input><link><meta>
  • 鲜见的有:<area><base><col><colgroup><command><embed><keygen><param><source><track><wbr>

px、em、rem的区别及应用场景

三者的区别:

  • px是固定的像素,一旦设置了就无奈因为适应页面大小而扭转。
  • em和rem绝对于px更具备灵活性,他们是绝对长度单位,其长度不是固定的,更实用于响应式布局。
  • em是绝对于其父元素来设置字体大小,这样就会存在一个问题,进行任何元素设置,都有可能须要晓得他父元素的大小。而rem是绝对于根元素,这样就意味着,只须要在根元素确定一个参考值。

应用场景:

  • 对于只须要适配少部分挪动设施,且分辨率对页面影响不大的,应用px即可 。
  • 对于须要适配各种挪动设施,应用rem,例如须要适配iPhone和iPad等分辨率差异比拟挺大的设施。

说一下slice splice split 的区别?

// slice(start,[end])// slice(start,[end])办法:该办法是对数组进行局部截取,该办法返回一个新数组// 参数start是截取的开始数组索引,end参数等于你要取的最初一个字符的地位值加上1(可选)。// 蕴含了源函数从start到 end 所指定的元素,然而不包含end元素,比方a.slice(0,3);// 如果呈现正数就把正数与长度相加后再划分。// slice中的正数的绝对值若大于数组长度就会显示所有数组// 若参数只有一个,并且参数大于length,则为空。// 如果完结地位小于起始地位,则返回空数组// 返回的个数是end-start的个数// 不会扭转原数组var arr = [1,2,3,4,5,6]/*console.log(arr.slice(3))//[4,5,6] 从下标为0的到3,截取3之后的数console.log(arr.slice(0,3))//[1,2,3] 从下标为0的中央截取到下标为3之前的数console.log(arr.slice(0,-2))//[1,2,3,4]console.log(arr.slice(-4,4))//[3,4]console.log(arr.slice(-7))//[1,2,3,4,5,6]console.log(arr.slice(-3,-3))// []console.log(arr.slice(8))//[]*/// 集体总结:slice的参数如果是负数就从左往右数,如果是正数的话就从右往左边数,// 截取的数组与数的方向统一,如果是2个参数则截取的是数的交加,没有交加则返回空数组 // ps:slice也能够切割字符串,用法和数组一样,但要留神空格也算字符// splice(start,deletecount,item)// start:起始地位// deletecount:删除位数// item:替换的item// 返回值为被删除的字符串// 如果有额定的参数,那么item会插入到被移除元素的地位上。// splice:移除,splice办法从array中移除一个或多个数组,并用新的item替换它们。//举一个简略的例子 var a=['a','b','c']; var b=a.splice(1,1,'e','f');  console.log(a) //['a', 'e', 'f', 'c'] console.log(b) //['b'] var a = [1, 2, 3, 4, 5, 6];//console.log("被删除的为:",a.splice(1, 1, 8, 9)); //被删除的为:2// console.log("a数组元素:",a); //1,8,9,3,4,5,6// console.log("被删除的为:", a.splice(0, 2)); //被删除的为:1,2// console.log("a数组元素:", a) //3,4,5,6console.log("被删除的为:", a.splice(1, 0, 2, 2)) //插入 第二个数为0,示意删除0个  console.log("a数组元素:", a) //1,2,2,2,3,4,5,6// split(字符串)// string.split(separator,limit):split办法把这个string宰割成片段来创立一个字符串数组。// 可选参数limit能够限度被宰割的片段数量。// separator参数能够是一个字符串或一个正则表达式。// 如果separator是一个空字符,会返回一个单字符的数组,不会扭转原数组。var a="0123456";  var b=a.split("",3);  console.log(b);//b=["0","1","2"]// 留神:String.split() 执行的操作与 Array.join 执行的操作是相同的。

Vuex有哪些根本属性?为什么 Vuex 的 mutation 中不能做异步操作?

有五种,别离是 State、 Getter、Mutation 、Action、 Module1、state => 根本数据(数据源寄存地)2、getters => 从根本数据派生进去的数据3、mutations => 提交更改数据的办法,同步4、actions => 像一个装璜器,包裹mutations,使之能够异步。5、modules => 模块化Vuex1、Vuex中所有的状态更新的惟一路径都是mutation,异步操作通过 Action 来提交 mutation实现,这样能够不便地跟踪每一个状态的变动,从而可能实现一些工具帮忙更好地理解咱们的利用。2、每个mutation执行实现后都会对应到一个新的状态变更,这样devtools就能够打个快照存下来,而后就能够实现 time-travel 了。如果mutation反对异步操作,就没有方法晓得状态是何时更新的,无奈很好的进行状态的追踪,给调试带来艰难。

说一下data为什么是一个函数而不是一个对象?

JavaScript中的对象是援用类型的数据,当多个实例援用同一个对象时,只有一个实例对这个对象进行操作,其余实例中的数据也会发生变化。而在Vue中,咱们更多的是想要复用组件,那就须要每个组件都有本人的数据,这样组件之间才不会互相烦扰。所以组件的数据不能写成对象的模式,而是要写成函数的模式。数据以函数返回值的模式定义,这样当咱们每次复用组件的时候,就会返回一个新的data,也就是说每个组件都有本人的公有数据空间,它们各自保护本人的数据,不会烦扰其余组件的失常运行。

说一说前端性能优化计划

三个方面来阐明前端性能优化一: webapck优化与开启gzip压缩    1.babel-loader用 include 或 exclude 来帮咱们防止不必要的转译,不转译node_moudules中的js文件    其次在缓存以后转译的js文件,设置loader: 'babel-loader?cacheDirectory=true'    2.文件采纳按需加载等等    3.具体的做法非常简单,只须要你在你的 request headers 中加上这么一句:    accept-encoding:gzip    4.图片优化,采纳svg图片或者字体图标    5.浏览器缓存机制,它又分为强缓存和协商缓存二:本地存储——从 Cookie 到 Web Storage、IndexedDB    阐明一下SessionStorage和localStorage还有cookie的区别和优缺点三:代码优化    1.事件代理    2.事件的节流和防抖    3.页面的回流和重绘    4.EventLoop事件循环机制    5.代码优化等等