精华内容
下载资源
问答
  • 前端面试题2021及答案

    万次阅读 多人点赞 2021-04-22 11:16:54
    身为三本的我就是凭借这些前端面试题拿到百度京东offer的,前端面试题2021及答案... 此文转载自:https://blog.csdn.net/qq_33277654/article/details/112758362#commentBox 点进来之后你的噩梦就要来了,接下来...

    身为三本的我就是凭借这些前端面试题拿到百度京东offer的,前端面试题2021及答案...

    此文转载自:https://blog.csdn.net/qq_33277654/article/details/112758362#commentBox

     

    点进来之后你的噩梦就要来了,接下来你要面对上百道面试题,那么,如果你——

    • 是个小白菜:
      • 推荐使用2~3周的时间来消化接下来的面试题,
      • 遇到不会的没听说过名词请立刻去搜;
      • 文章中只是简答,如果想要详细了解的话还需要你自觉去搜索
    • 如果你是个大神:
      • 好叭先给您拜个早年,大哥大嫂过年好。
      • 请温柔点黑我。

    顺便,如果有错误的地方请各位一定要指出,免得误导更多人。
    接下来的题我会根据重点程度使用⭐来标记,⭐越多标明越重点,满星是5颗星
    ok,你准备好了吗?咱们开始吧!

     

    在这里插入图片描述

    JS

    数据类型

    面试官:JavaScript中什么是基本数据类型什么是引用数据类型?以及各个数据类型是如何存储的?⭐⭐⭐⭐⭐

    答:
    基本数据类型有

    • Number
    • String
    • Boolean
    • Null
    • Undefined
    • Symbol(ES6新增数据类型)
    • bigInt

    引用数据类型统称为Object类型,细分的话有

    • Object
    • Array
    • Date
    • Function
    • RegExp

    基本数据类型的数据直接存储在栈中;而引用数据类型的数据存储在堆中,每个对象在堆中有一个引用地址。引用类型在栈中会保存他的引用地址,以便快速查找到堆内存中的对象。

    顺便提一句,栈内存是自动分配内存的。而堆内存是动态分配内存的,不会自动释放。所以每次使用完对象的时候都要把它设置为null,从而减少无用内存的消耗

    类型转换

    面试官:在JS中为什么0.2+0.1>0.3?⭐⭐⭐⭐

    答:

    因为在JS中,浮点数是使用64位固定长度来表示的,其中的1位表示符号位,11位用来表示指数位,剩下的52位尾数位,由于只有52位表示尾数位。

    0.1转为二进制是一个无限循环数0.0001100110011001100......(1100循环)

    小数的十进制转二进制方法:https://jingyan.baidu.com/article/425e69e6e93ca9be15fc1626.html
    要知道,小数的十进制转二进制的方法是和整数不一样的,推荐看一看

    由于只能存储52位尾数位,所以会出现精度缺失,把它存到内存中再取出来转换成十进制就不是原来的0.1了,就变成了0.100000000000000005551115123126,而为什么02+0.1是因为

    // 0.1 和 0.2 都转化成二进制后再进行运算
    0.00011001100110011001100110011001100110011001100110011010 +
    0.0011001100110011001100110011001100110011001100110011010 =
    0.0100110011001100110011001100110011001100110011001100111
     
    // 转成十进制正好是 0.30000000000000004
    
    
    
     

    面试官:那为什么0.2+0.3=0.5呢?⭐⭐⭐⭐

    // 0.2 和 0.3 都转化为二进制后再进行计算
    0.001100110011001100110011001100110011001100110011001101 +
    0.0100110011001100110011001100110011001100110011001101 = 
    0.10000000000000000000000000000000000000000000000000001 //尾数为大于52位
     
    // 而实际取值只取52位尾数位,就变成了
    0.1000000000000000000000000000000000000000000000000000   //0.5
    
     

    答:0.20.3分别转换为二进制进行计算:在内存中,它们的尾数位都是等于52位的,而他们相加必定大于52位,而他们相加又恰巧前52位尾数都是0,截取后恰好是0.1000000000000000000000000000000000000000000000000000也就是0.5

    面试官:那既然0.1不是0.1了,为什么在console.log(0.1)的时候还是0.1呢?⭐⭐⭐

    答:console.log的时候会二进制转换为十进制,十进制再会转为字符串的形式,在转换的过程中发生了取近似值,所以打印出来的是一个近似值的字符串

    面试官:判断数据类型有几种方法⭐⭐⭐⭐⭐

    答:

    • typeof

      • 缺点:typeof null的值为Object,无法分辨是null还是Object
    • instanceof

      • 缺点:只能判断对象是否存在于目标对象的原型链上
    • constructor

    • Object.prototype.toString.call()

      • 一种最好的基本类型检测方式 Object.prototype.toString.call() ;它可以区分 null 、 string 、

        boolean 、 number 、 undefined 、 array 、 function 、 object 、 date 、 math 数据类型。

      • 缺点:不能细分为谁谁的实例

    // -----------------------------------------typeof
        typeof undefined // 'undefined' 
        typeof '10' // 'String' 
        typeof 10 // 'Number' 
        typeof false // 'Boolean' 
        typeof Symbol() // 'Symbol' 
        typeof Function // ‘function' 
        typeof null // ‘Object’ 
        typeof [] // 'Object' 
        typeof {} // 'Object'
     
     
        // -----------------------------------------instanceof
        function Foo() { }
        var f1 = new Foo();
        var d = new Number(1)
     
     
        console.log(f1 instanceof Foo);// true
        console.log(d instanceof Number); //true
        console.log(123 instanceof Number); //false   -->不能判断字面量的基本数据类型
     
     
        // -----------------------------------------constructor
        var d = new Number(1)
        var e = 1
        function fn() {
          console.log("ming");
        }
        var date = new Date();
        var arr = [1, 2, 3];
        var reg = /[hbc]at/gi;
     
        console.log(e.constructor);//ƒ Number() { [native code] }
        console.log(e.constructor.name);//Number
        console.log(fn.constructor.name) // Function 
        console.log(date.constructor.name)// Date 
        console.log(arr.constructor.name) // Array 
        console.log(reg.constructor.name) // RegExp
     
     
     
     
        //-----------------------------------------Object.prototype.toString.call()
        console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]" 
        console.log(Object.prototype.toString.call(null)); // "[object Null]" 
        console.log(Object.prototype.toString.call(123)); // "[object Number]" 
        console.log(Object.prototype.toString.call("abc")); // "[object String]" 
        console.log(Object.prototype.toString.call(true)); // "[object Boolean]" 
     
     
        function fn() {
          console.log("ming");
        }
        var date = new Date();
        var arr = [1, 2, 3];
        var reg = /[hbc]at/gi;
        console.log(Object.prototype.toString.call(fn));// "[object Function]" 
        console.log(Object.prototype.toString.call(date));// "[object Date]" 
        console.log(Object.prototype.toString.call(arr)); // "[object Array]"
        console.log(Object.prototype.toString.call(reg));// "[object RegExp]"
    
    

     

     

    instanceof原理⭐⭐⭐⭐⭐

    • instanceof原理实际上就是查找目标对象的原型链
    function myInstance(L, R) {//L代表instanceof左边,R代表右边
          var RP = R.prototype
          var LP = L.__proto__
          while (true) {
            if(LP == null) {
              return false
            }
            if(LP == RP) {
              return true
            }
            LP = LP.__proto__
          }
        }
        console.log(myInstance({},Object)); 
        
    

     

     

    面试官:为什么typeof null是Object⭐⭐⭐⭐

    答:

    因为在JavaScript中,不同的对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全是0,自然也就判断为Object

    这个bug是初版本的JavaScript中留下的,扩展一下其他五种标识位:

    • 000 对象
    • 1 整型
    • 010 双精度类型
    • 100字符串
    • 110布尔类型

    面试官:=====有什么区别⭐⭐⭐⭐⭐

    答:

    ===是严格意义上的相等,会比较两边的数据类型和值大小

    • 数据类型不同返回false
    • 数据类型相同,但值大小不同,返回false

    ==是非严格意义上的相等,

    • 两边类型相同,比较大小

    • 两边类型不同,根据下方表格,再进一步进行比较。

      • Null == Undefined ->true
      • String == Number ->先将String转为Number,在比较大小
      • Boolean == Number ->现将Boolean转为Number,在进行比较
      • Object == String,Number,Symbol -> Object 转化为原始类型

    面试官:手写call、apply、bind⭐⭐⭐⭐⭐

    答:

    • call和apply实现思路主要是:
      • 判断是否是函数调用,若非函数调用抛异常
      • 通过新对象(context)来调用函数
        • 给context创建一个fn设置为需要调用的函数
        • 结束调用完之后删除fn
    • bind实现思路
      • 判断是否是函数调用,若非函数调用抛异常
      • 返回函数
        • 判断函数的调用方式,是否是被new出来的
          • new出来的话返回空对象,但是实例的__proto__指向_thisprototype
      • 完成函数柯里化
        • Array.prototype.slice.call()

    call:

    Function.prototype.myCall = function (context) {
          // 先判断调用myCall是不是一个函数
          // 这里的this就是调用myCall的
          if (typeof this !== 'function') {
            throw new TypeError("Not a Function")
          }
     
          // 不传参数默认为window
          context = context || window
     
          // 保存this
          context.fn = this
     
          // 保存参数
          let args = Array.from(arguments).slice(1)   //Array.from 把伪数组对象转为数组
     
          // 调用函数
          let result = context.fn(...args)
     
          delete context.fn
     
          return result
     
        }
    
    
     

    apply

    Function.prototype.myApply = function (context) {
          // 判断this是不是函数
          if (typeof this !== "function") {
            throw new TypeError("Not a Function")
          }
     
          let result
     
          // 默认是window
          context = context || window
     
          // 保存this
          context.fn = this
     
          // 是否传参
          if (arguments[1]) {
            result = context.fn(...arguments[1])
          } else {
            result = context.fn()
          }
          delete context.fn
     
          return result
        }
     
    
    
     

    bind

    Function.prototype.myBind = function(context){
          // 判断是否是一个函数
          if(typeof this !== "function") {
            throw new TypeError("Not a Function")
          }
          // 保存调用bind的函数
          const _this = this 
          // 保存参数
          const args = Array.prototype.slice.call(arguments,1)
          // 返回一个函数
          return function F () {
            // 判断是不是new出来的
            if(this instanceof F) {
              // 如果是new出来的
              // 返回一个空对象,且使创建出来的实例的__proto__指向_this的prototype,且完成函数柯里化
              return new _this(...args,...arguments)
            }else{
              // 如果不是new出来的改变this指向,且完成函数柯里化
              return _this.apply(context,args.concat(...arguments))
            }
          } 
        }
    
     

    面试官:字面量创建对象和new创建对象有什么区别,new内部都实现了什么,手写一个new⭐⭐⭐⭐⭐

    答:

    字面量:

    • 字面量创建对象更简单,方便阅读
    • 不需要作用域解析,速度更快

    new内部:

    • 创建一个新对象
    • 使新对象的__proto__指向原函数的prototype
    • 改变this指向(指向新的obj)并执行该函数,执行结果保存起来作为result
    • 判断执行函数的结果是不是null或Undefined,如果是则返回之前的新对象,如果不是则返回result

    手写new

    // 手写一个new
        function myNew(fn, ...args) {
          // 创建一个空对象
          let obj = {}
          // 使空对象的隐式原型指向原函数的显式原型
          obj.__proto__ = fn.prototype
          // this指向obj
          let result = fn.apply(obj, args)
          // 返回
          return result instanceof Object ? result : obj
        }
    
     

    面试官:字面量new出来的对象和 Object.create(null)创建出来的对象有什么区别⭐⭐⭐

    答:

    • 字面量和new创建出来的对象会继承Object的方法和属性,他们的隐式原型会指向Object的显式原型,

    • Object.create(null)创建出来的对象原型为null,作为原型链的顶端,自然也没有继承Object的方法和属性

    执行栈和执行上下文

    面试官:什么是作用域,什么是作用域链?⭐⭐⭐⭐

    答:

    • 规定变量和函数的可使用范围称作作用域
    • 每个函数都有一个作用域链,查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作作用域链。

    面试官:什么是执行栈,什么是执行上下文?⭐⭐⭐⭐

    答:

    执行上下文分为:

    • 全局执行上下文
      • 创建一个全局的window对象,并规定this指向window,执行js的时候就压入栈底,关闭浏览器的时候才弹出
    • 函数执行上下文
      • 每次函数调用时,都会新创建一个函数执行上下文
      • 执行上下文分为创建阶段和执行阶段
        • 创建阶段:函数环境会创建变量对象:arguments对象(并赋值)、函数声明(并赋值)、变量声明(不赋值),函数表达式声明(不赋值);会确定this指向;会确定作用域
        • 执行阶段:变量赋值、函数表达式赋值,使变量对象编程活跃对象
    • eval执行上下文

    执行栈:

    • 首先栈特点:先进后出
    • 当进入一个执行环境,就会创建出它的执行上下文,然后进行压栈,当程序执行完成时,它的执行上下文就会被销毁,进行弹栈。
    • 栈底永远是全局环境的执行上下文,栈顶永远是正在执行函数的执行上下文
    • 只有浏览器关闭的时候全局执行上下文才会弹出

    闭包

    很多人都吃不透js闭包,这里推荐一篇文章:彻底理解js中的闭包

    面试官:什么是闭包?闭包的作用?闭包的应用?⭐⭐⭐⭐⭐

    答:

    函数执行,形成私有的执行上下文,使内部私有变量不受外界干扰,起到保护保存的作用

    作用:

    • 保护
      • 避免命名冲突
    • 保存
      • 解决循环绑定引发的索引问题
    • 变量不会销毁
      • 可以使用函数内部的变量,使变量不会被垃圾回收机制回收

    应用:

    • 设计模式中的单例模式
    • for循环中的保留i的操作
    • 防抖和节流
    • 函数柯里化

    缺点

    • 会出现内存泄漏的问题

    原型和原型链

    面试官:什么是原型?什么是原型链?如何理解⭐⭐⭐⭐⭐

    答:

    原型: 原型分为隐式原型和显式原型,每个对象都有一个隐式原型,它指向自己的构造函数的显式原型。

    原型链: 多个__proto__组成的集合成为原型链

    • 所有实例的__proto__都指向他们构造函数的prototype
    • 所有的prototype都是对象,自然它的__proto__指向的是Object()prototype
    • 所有的构造函数的隐式原型指向的都是Function()的显示原型
    • Object的隐式原型是null

    继承

    面试官:说一说 JS 中的常用的继承方式有哪些?以及各个继承方式的优缺点。⭐⭐⭐⭐⭐

    答:

    原型继承、组合继承、寄生组合继承、ES6的extend

    原型继承

    // ----------------------方法一:原型继承
        // 原型继承
        // 把父类的实例作为子类的原型
        // 缺点:子类的实例共享了父类构造函数的引用属性   不能传参
     
        var person = {
          friends: ["a", "b", "c", "d"]
        }
     
        var p1 = Object.create(person)
     
        p1.friends.push("aaa")//缺点:子类的实例共享了父类构造函数的引用属性
     
        console.log(p1);
        console.log(person);//缺点:子类的实例共享了父类构造函数的引用属性
    
    
     

    组合继承

    // ----------------------方法二:组合继承
        // 在子函数中运行父函数,但是要利用call把this改变一下,
        // 再在子函数的prototype里面new Father() ,使Father的原型中的方法也得到继承,最后改变Son的原型中的constructor
     
        // 缺点:调用了两次父类的构造函数,造成了不必要的消耗,父类方法可以复用
        // 优点可传参,不共享父类引用属性
        function Father(name) {
          this.name = name
          this.hobby = ["篮球", "足球", "乒乓球"]
        }
     
        Father.prototype.getName = function () {
          console.log(this.name);
        }
     
        function Son(name, age) {
          Father.call(this, name)
          this.age = age
        }
     
        Son.prototype = new Father()
        Son.prototype.constructor = Son
     
     
        var s = new Son("ming", 20)
     
        console.log(s);
    
    
     

    寄生组合继承

    // ----------------------方法三:寄生组合继承
        function Father(name) {
          this.name = name
          this.hobby = ["篮球", "足球", "乒乓球"]
        }
     
        Father.prototype.getName = function () {
          console.log(this.name);
        }
     
        function Son(name, age) {
          Father.call(this, name)
          this.age = age
        }
     
        Son.prototype = Object.create(Father.prototype)
        Son.prototype.constructor = Son
     
        var s2 = new Son("ming", 18)
        console.log(s2);
    
    
     

    extend

    // ----------------------方法四:ES6的extend(寄生组合继承的语法糖)
        //     子类只要继承父类,可以不写 constructor ,一旦写了,则在 constructor 中的第一句话
        // 必须是 super 。
     
        class Son3 extends Father { // Son.prototype.__proto__ = Father.prototype
          constructor(y) {
            super(200)  // super(200) => Father.call(this,200)
            this.y = y
          }
        }
    
     

    内存泄露、垃圾回收机制

    面试官:什么是内存泄漏⭐⭐⭐⭐⭐

    答:

    ​ 内存泄露是指不再用的内存没有被及时释放出来,导致该段内存无法被使用就是内存泄漏

    面试官:为什么会导致的内存泄漏⭐⭐⭐⭐⭐

    答:

    内存泄漏指我们无法在通过js访问某个对象,而垃圾回收机制却认为该对象还在被引用,因此垃圾回收机制不会释放该对象,导致该块内存永远无法释放,积少成多,系统会越来越卡以至于崩溃

    面试官:垃圾回收机制都有哪些策略?⭐⭐⭐⭐⭐

    答:

    • 标记清除法
      • 垃圾回收机制获取根并标记他们,然后访问并标记所有来自它们的引用,然后在访问这些对象并标记它们的引用…如此递进结束后若发现有没有标记的(不可达的)进行删除,进入执行环境的不能进行删除
    • 引用计数法
      • 当声明一个变量并给该变量赋值一个引用类型的值时候,该值的计数+1,当该值赋值给另一个变量的时候,该计数+1,当该值被其他值取代的时候,该计数-1,当计数变为0的时候,说明无法访问该值了,垃圾回收机制清除该对象

    深拷贝和浅拷贝

    手写浅拷贝深拷贝⭐⭐⭐⭐⭐

    // ----------------------------------------------浅拷贝
        // 只是把对象的属性和属性值拷贝到另一个对象中
        var obj1 = {
          a: {
            a1: { a2: 1 },
            a10: { a11: 123, a111: { a1111: 123123 } }
          },
          b: 123,
          c: "123"
        }
        // 方式1
        function shallowClone1(o) {
          let obj = {}
     
          for (let i in o) {
            obj[i] = o[i]
          }
          return obj
        }
     
        // 方式2
        var shallowObj2 = { ...obj1 }
     
        // 方式3
        var shallowObj3 = Object.assign({}, obj1)
     
        let shallowObj = shallowClone1(obj1);
     
        shallowObj.a.a1 = 999
        shallowObj.b = true
     
        console.log(obj1);  //第一层的没有被改变,一层以下就被改变了
     
     
     
        // ----------------------------------------------深拷贝
     
        // 简易版  
        function deepClone(o) {
          let obj = {}
          for (var i in o) {
            // if(o.hasOwnProperty(i)){
            if (typeof o[i] === "object") {
              obj[i] = deepClone(o[i])
            } else {
              obj[i] = o[i]
            }
            // }
          }
          return obj
        }
     
     
        var myObj = {
          a: {
            a1: { a2: 1 },
            a10: { a11: 123, a111: { a1111: 123123 } }
          },
          b: 123,
          c: "123"
        }
     
        var deepObj1 = deepClone(myObj)
        deepObj1.a.a1 = 999
        deepObj1.b = false
        console.log(myObj);
     
     
     
        // 简易版存在的问题:参数没有做检验,传入的可能是 Array、null、regExp、Date
        function deepClone2(o) {
          if (Object.prototype.toString.call(o) === "[object Object]") {  //检测是否为对象
            let obj = {}
            for (var i in o) {
              if (o.hasOwnProperty(i)) {
                if (typeof o[i] === "object") {
                  obj[i] = deepClone(o[i])
                } else {
                  obj[i] = o[i]
                }
              }
            }
            return obj
          } else {
            return o
          }
        }
     
        function isObject(o) {
          return Object.prototype.toString.call(o) === "[object Object]" || Object.prototype.toString.call(o) === "[object Array]"
        }
     
        // 继续升级,没有考虑到数组,以及ES6中的map、set、weakset、weakmap
        function deepClone3(o) {
          if (isObject(o)) {//检测是否为对象或者数组
            let obj = Array.isArray(o) ? [] : {}
            for (let i in o) {
              if (isObject(o[i])) {
                obj[i] = deepClone(o[i])
              } else {
                obj[i] = o[i]
              }
            }
            return obj
          } else {
            return o
          }
        }
     
     
        // 有可能碰到循环引用问题  var a = {}; a.a = a; clone(a);//会造成一个死循环
        // 循环检测
        // 继续升级
        function deepClone4(o, hash = new map()) {
          if (!isObject(o)) return o//检测是否为对象或者数组
          if (hash.has(o)) return hash.get(o)
          let obj = Array.isArray(o) ? [] : {}
     
          hash.set(o, obj)
          for (let i in o) {
            if (isObject(o[i])) {
              obj[i] = deepClone4(o[i], hash)
            } else {
              obj[i] = o[i]
            }
          }
          return obj
        }
     
        // 递归易出现爆栈问题
        //  将递归改为循环,就不会出现爆栈问题了
        var a1 = { a: 1, b: 2, c: { c1: 3, c2: { c21: 4, c22: 5 } }, d: 'asd' };
        var b1 = { b: { c: { d: 1 } } }
        function cloneLoop(x) {
          const root = {};
          // 栈 
          const loopList = [  //->[]->[{parent:{a:1,b:2},key:c,data:{ c1: 3, c2: { c21: 4, c22: 5 } }}]
            {
              parent: root,
              key: undefined,
              data: x,
            }
          ];
          while (loopList.length) {
            // 深度优先
            const node = loopList.pop();
            const parent = node.parent; //{} //{a:1,b:2}
            const key = node.key; //undefined //c
            const data = node.data; //{ a: 1, b: 2, c: { c1: 3, c2: { c21: 4, c22: 5 } }, d: 'asd' }  //{ c1: 3, c2: { c21: 4, c22: 5 } }}
            // 初始化赋值目标,key 为 undefined 则拷贝到父元素,否则拷贝到子元素
            let res = parent; //{}->{a:1,b:2,d:'asd'} //{a:1,b:2}->{}
            if (typeof key !== 'undefined') {
              res = parent[key] = {};
            }
            for (let k in data) {
              if (data.hasOwnProperty(k)) {
                if (typeof data[k] === 'object') {
                  // 下一次循环 
                  loopList.push({
                    parent: res,
                    key: k,
                    data: data[k],
                  })
                } else {
                  res[k] = data[k];
                }
              }
            }
          }
          return root
        }
     
     
        function deepClone5(o) {
          let result = {}
          let loopList = [
            {
              parent: result,
              key: undefined,
              data: o
            }
          ]
     
          while (loopList.length) {
            let node = loopList.pop()
            let { parent, key, data } = node
            let anoPar = parent
            if (typeof key !== 'undefined') {
              anoPar = parent[key] = {}
            }
     
            for (let i in data) {
              if (typeof data[i] === 'object') {
                loopList.push({
                  parent: anoPar,
                  key: i,
                  data: data[i]
                })
              } else {
                anoPar[i] = data[i]
              }
            }
          }
          return result
        }
     
     
        let cloneA1 = deepClone5(a1)
        cloneA1.c.c2.c22 = 5555555
        console.log(a1);
        console.log(cloneA1);
     
     
        // ------------------------------------------JSON.stringify()实现深拷贝
     
        function cloneJson(o) {
          return JSON.parse(JSON.stringify(o))
        }
     
        // let obj = { a: { c: 1 }, b: {} };
        // obj.b = obj;
        // console.log(JSON.parse(JSON.stringify(obj))) // 报错 // Converting circular structure to JSON
     
    
     

    深拷贝能使用hash递归的方式写出来就可以了
    不过技多不压身,推荐还是看一看使用while实现深拷贝方法

    单线程,同步异步

    面试官:为什么JS是单线程的?⭐⭐⭐⭐⭐

    **答:**因为JS里面有可视的Dom,如果是多线程的话,这个线程正在删除DOM节点,另一个线程正在编辑Dom节点,导致浏览器不知道该听谁的

    面试官:如何实现异步编程?

    **答:**回调函数

    面试官:Generator是怎么样使用的以及各个阶段的变化如何?⭐⭐⭐

    答:

    • 首先生成器是一个函数,用来返回迭代器的

    • 调用生成器后不会立即执行,而是通过返回的迭代器来控制这个生成器的一步一步执行的

    • 通过调用迭代器的next方法来请求一个一个的值,返回的对象有两个属性,一个是value,也就是值;另一个是done,是个布尔类型,done为true说明生成器函数执行完毕,没有可返回的值了,

    • donetrue后继续调用迭代器的next方法,返回值的valueundefined

    状态变化:

    • 每当执行到yield属性的时候,都会返回一个对象
    • 这时候生成器处于一个非阻塞的挂起状态
    • 调用迭代器的next方法的时候,生成器又从挂起状态改为执行状态,继续上一次的执行位置执行
    • 直到遇到下一次yield依次循环
    • 直到代码没有yield了,就会返回一个结果对象donetruevalueundefined

    面试官:说说 Promise 的原理?你是如何理解 Promise 的?⭐⭐⭐⭐⭐

    • 做到会写简易版的promise和all函数就可以

    答:

    class MyPromise2 {
          constructor(executor) {
            // 规定状态
            this.state = "pending"
            // 保存 `resolve(res)` 的res值
            this.value = undefined
            // 保存 `reject(err)` 的err值
            this.reason = undefined
            // 成功存放的数组
            this.successCB = []
            // 失败存放的数组
            this.failCB = []
     
     
            let resolve = (value) => {
              if (this.state === "pending") {
                this.state = "fulfilled"
                this.value = value
                this.successCB.forEach(f => f())
              }
            }
            let reject = (reason) => {
              if (this.state === "pending") {
                this.state = "rejected"
                this.value = value
                this.failCB.forEach(f => f())
              }
            }
     
            try {
              // 执行
              executor(resolve, reject)
            } catch (error) {
              // 若出错,直接调用reject
              reject(error)
            }
          }
          then(onFulfilled, onRejected) {
            if (this.state === "fulfilled") {
              onFulfilled(this.value)
            }
            if (this.state === "rejected") {
              onRejected(this.value)
            }
            if (this.state === "pending") {
              this.successCB.push(() => { onFulfilled(this.value) })
              this.failCB.push(() => { onRejected(this.reason) })
            }
          }
        }
     
     
        Promise.all = function (promises) {
          let list = []
          let count = 0
          function handle(i, data) {
            list[i] = data
            count++
            if (count == promises.length) {
              resolve(list)
            }
          }
          return Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
              promises[i].then(res => {
                handle(i, res)
              }, err => reject(err))
            }
          })
        }
    
     

    面试官:以下代码的执行顺序是什么⭐⭐⭐⭐⭐

    答:

    async function async1() {
       console.log('async1 start')
       await async2()
       console.log('async1 end')
      }
      async function async2() {
       console.log('async2')
      }
      async1()
      console.log('script start')
     
    //执行到await时,如果返回的不是一个promise对象,await会阻塞下面代码(当前async代码块的代码),会先执行async外的同步代码(在这之前先看看await中函数的同步代码,先把同步代码执行完),等待同步代码执行完之后,再回到async内部继续执行
    //执行到await时,如果返回的是一个promise对象,await会阻塞下面代码(当前async代码块的代码),会先执行async外的同步代码(在这之前先看看await中函数的同步代码,先把同步代码执行完),等待同步代码执行完之后,再回到async内部等promise状态达到fulfill的时候再继续执行下面的代码
    //所以结果为
    //async1 start
    //async2
    //script start
    //async1 end
    
    
     

    面试官:宏任务和微任务都有哪些⭐⭐⭐⭐⭐

    答:

    • 宏任务:scriptsetTimeOutsetIntervalsetImmediate
    • 微任务:promise.then,process.nextTickObject.observeMutationObserver
    • 注意:Promise是同步任务

    面试官:宏任务和微任务都是怎样执行的⭐⭐⭐⭐⭐

    答:

    • 执行宏任务script,
    • 进入script后,所有的同步任务主线程执行
    • 所有宏任务放入宏任务执行队列
    • 所有微任务放入微任务执行队列
    • 先清空微任务队列,
    • 再取一个宏任务,执行,再清空微任务队列
    • 依次循环

    例题1

    setTimeout(function(){
        console.log('1')
    });
    new Promise(function(resolve){
        console.log('2');
        resolve();
    }).then(function(){
        console.log('3')
    });
    console.log('4');
    new Promise(function(resolve){
        console.log('5');
        resolve();
    }).then(function(){
        console.log('6')
    });
    setTimeout(function(){
        console.log('7')
    });
    function bar(){
        console.log('8')
        foo()
    }
    function foo(){
        console.log('9')
    }
    console.log('10')
    bar()
    
    
     

    解析

    1. 首先浏览器执行Js代码由上至下顺序,遇到setTimeout,把setTimeout分发到宏任务Event Queue中
    2. new Promise属于主线程任务直接执行打印2
    3. Promis下的then方法属于微任务,把then分到微任务 Event Queue中
    4. console.log(‘4’)属于主线程任务,直接执行打印4
    5. 又遇到new Promise也是直接执行打印5,Promise 下到then分发到微任务Event Queue中
    6. 又遇到setTimouse也是直接分发到宏任务Event Queue中,等待执行
    7. console.log(‘10’)属于主线程任务直接执行
    8. 遇到bar()函数调用,执行构造函数内到代码,打印8,在bar函数中调用foo函数,执行foo函数到中代码,打印9
    9. 主线程中任务执行完后,就要执行分发到微任务Event Queue中代码,实行先进先出,所以依次打印3,6
    10. 微任务Event Queue中代码执行完,就执行宏任务Event Queue中代码,也是先进先出,依次打印1,7。
    • 最终结果:2,4,5,10,8,9,3,6,1,7

    例题2

    setTimeout(() => {
          console.log('1');
          new Promise(function (resolve, reject) {
            console.log('2');
            setTimeout(() => {
              console.log('3');
            }, 0);
            resolve();
          }).then(function () {
            console.log('4')
          })
        }, 0);
        console.log('5'); //5 7 10 8 1 2 4 6 3
        setTimeout(() => {
          console.log('6');
        }, 0);
        new Promise(function (resolve, reject) {
          console.log('7');
          // reject();
          resolve();
        }).then(function () {
          console.log('8')
        }).catch(function () {
          console.log('9')
        })
        console.log('10');
    
    
     

    运行结果: 5 7 10 8 1 2 4 6 3

    变量提升

    面试官:变量和函数怎么进行提升的?优先级是怎么样的?⭐⭐⭐⭐

    答:

    • 对所有函数声明进行提升(除了函数表达式和箭头函数),引用类型的赋值
      • 开辟堆空间
      • 存储内容
      • 将地址赋给变量
    • 对变量进行提升,只声明,不赋值,值为undefined

    面试官:var let const 有什么区别⭐⭐⭐⭐⭐

    答:

    • var
      • var声明的变量可进行变量提升,let和const不会
      • var可以重复声明
      • var在非函数作用域中定义是挂在到window上的
    • let
      • let声明的变量只在局部起作用
      • let防止变量污染
      • 不可在声明
    • const
      • 具有let的所有特征
      • 不可被改变
        • 如果使用const声明的是对象的话,是可以修改对象里面的值的

    面试官:箭头函数和普通函数的区别?箭头函数可以当做构造函数 new 吗?⭐⭐⭐⭐⭐

    • 箭头函数是普通函数的简写,但是它不具备很多普通函数的特性
    • 第一点,this指向问题,箭头函数的this指向它定义时所在的对象,而不是调用时所在的对象
    • 不会进行函数提升
    • 没有arguments对象,不能使用arguments,如果要获取参数的话可以使用rest运算符
    • 没有yield属性,不能作为生成器Generator使用
    • 不能new
      • 没有自己的this,不能调用call和apply
      • 没有prototype,new关键字内部需要把新对象的_proto_指向函数的prototype

    面试官:说说你对代理的理解⭐⭐⭐

    • 代理有几种定义方式
      • 字面量定义,对象里面的 get和set
      • 类定义, class 中的getset
      • Proxy对象,里面传两个对象,第一个对象是目标对象target,第二个对象是专门放get和set的handler对象。Proxy和上面两个的区别在于Proxy专门对对象的属性进行get和set
    • 代理的实际应用有
      • Vue的双向绑定 vue2用的是Object.defineProperty,vue3用的是proxy
      • 校验值
      • 计算属性值(get的时候加以修饰)

    面试官:为什么要使用模块化?都有哪几种方式可以实现模块化,各有什么特点?⭐⭐⭐

    • 为什么要使用模块化
      • 防止命名冲突
      • 更好的分离,按需加载
      • 更好的复用性
      • 更高的维护性

    面试官:exportsmodule.exports有什么区别?⭐⭐⭐

    • 导出方式不一样
      • exports.xxx='xxx'
      • module.export = {}
    • exportsmodule.exports的引用,两个指向的是用一个地址,而require能看到的只有module.exports

    面试官:JS模块包装格式有哪些?⭐⭐⭐

    • commonjs

      • 同步运行,不适合前端
    • AMD

      • 异步运行
      • 异步模块定义,主要采用异步的方式加载模块,模块的加载不影响后面代码的执行。所有依赖这个模块的语句都写在一个回调函数中,模块加载完毕,再执行回调函数
    • CMD

      • 异步运行
      • seajs 规范

    面试官:ES6和commonjs的区别⭐⭐⭐

    • commonjs模块输出的是值的拷贝,而ES6输出的值是值的引用
    • commonjs是在运行时加载,是一个对象,ES6是在编译时加载,是一个代码块
    • commonjs的this指向当前模块,ES6的this指向undefined

    哎呀呀呀,不简单,你竟然都看到这里了,看看进度条,已经达到一半了
    不过——在这之前,先问问自己,前面的都掌握了吗??
    如果你还没有,赶紧滚回去看!
    如果你掌握前面的了,那么准备迎接下一个boss——计算机网络

     

    在这里插入图片描述

    跨域

    面试官:跨域的方式都有哪些?他们的特点是什么 ⭐⭐⭐⭐⭐

    • JSONP⭐⭐⭐⭐⭐

      • JSONP通过同源策略涉及不到的"漏洞",也就是像img中的srclink标签的href,scriptsrc都没有被同源策略限制到

      • JSONP只能get请求

      • 源码:

        function addScriptTag(src) {
              var script = document.createElement("script")
              script.setAttribute('type','text/javascript')
              script.src = src
              document.appendChild(script)
            }
         
            
            // 回调函数
            function endFn(res) {
              console.log(res.message);
            }
         
            // 前后端商量好,后端如果传数据的话,返回`endFn({message:'hello'})`
        
        

         

    • document.domain⭐

      • 只能跨一级域名相同的域(www.qq.om和www.id.qq.com , 二者都有qq.com)

      • 使用方法

        • >表示输入, <表示输出 ,以下是在www.id.qq.com网站下执行的操作

        • > var w = window.open("https://www.qq.com")
          < undefined
          > w.document
          ✖ VM3061:1 Uncaught DOMException: Blocked a frame with origin "https://id.qq.com" from accessing a cross-origin frame.
              at <anonymous>:1:3
          > document.domain
          < "id.qq.com"
          > document.domain = 'qq.com'
          < "qq.com"
          > w.document
          < #document
          
          

           

    • location.hash+iframe⭐⭐

      • 因为hash传值只能单向传输,所有可以通过一个中间网页,a若想与b进行通信,可以通过一个与a同源的c作为中间网页,a传给b,b传给c,c再传回a

        • 具体做法:在a中放一个回调函数,方便c回调。放一个iframe标签,随后传值

        • <iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
          <script>
              var iframe = document.getElementById('iframe');
           
              // 向b.html传hash值
              setTimeout(function() {
                  iframe.src = iframe.src + '#user=admin';
              }, 1000);
              
              // 开放给同域c.html的回调方法
              function onCallback(res) {
                  alert('data from c.html ---> ' + res);
              }
          </script>
          
          

           

        • 在b中监听哈希值改变,一旦改变,把a要接收的值传给

        • <iframe id="iframe" src="http://www.domain1.com/c.html" style="display:none;"></iframe>
          <script>
              var iframe = document.getElementById('iframe');
           
              // 监听a.html传来的hash值,再传给c.html
              window.onhashchange = function () {
                  iframe.src = iframe.src + location.hash;
              };
          </script>
          
          

           

        • 在c中监听哈希值改变,一旦改变,调用a中的回调函数

        • <script>
              // 监听b.html传来的hash值
              window.onhashchange = function () {
                  // 再通过操作同域a.html的js回调,将结果传回
                  window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', ''));
              };
          </script>
          

           

    • window.name+iframe⭐⭐

      • 利Access用window.name不会改变(而且很大)来获取数据,
      • a要获取b的数据,b中把数据转为json格式放到window.name
    • postMessage

      • a窗口向b窗口发送数据,先把data转为json格式,在发送。提前设置好messge监听
      • b窗口进行message监听,监听到了以同样的方式返回数据,
      • a窗口监听到message,在进行一系列操作
    • CORS⭐⭐⭐⭐⭐

      • 通过自定义请求头来让服务器和浏览器进行沟通
      • 有简单请求和非简单请求
      • 满足以下条件,就是简单请求
        • 请求方法是HEAD、POST、GET
        • 请求头只有AcceptAcceptLanguageContentTypeContentLanguageLast-Event-Id
      • 简单请求,浏览器自动添加一个Origin字段
        • 同时后端需要设置的请求头
          • Access-Control-Allow-Origin --必须
          • Access-Control-Expose-Headers
            • XMLHttpRequest只能拿到六个字段,要想拿到其他的需要在这里指定
        • Access-Control-Allow-Credentials --是否可传cookie
        • 要是想传cookie,前端需要设置xhr.withCredentials = true,后端设置Access-Control-Allow-Credentials
      • 非简单请求,浏览器判断是否为简单请求,如果是非简单请求,则 浏览器先发送一个header头为option的请求进行预检
        • 预检请求格式(请求行 的请求方法为OPTIONS(专门用来询问的))
          • Origin
          • Access-Control-Request-Method
          • Access-Control-Request-Header
        • 浏览器检查了Origin、Access-Control-Allow-Method和Access-Control-Request-Header之后确认允许就可以做出回应了
        • 通过预检后,浏览器接下来的每次请求就类似于简单请求了
    • nginx代理跨域⭐⭐⭐⭐

      • nginx模拟一个虚拟服务器,因为服务器与服务器之间是不存在跨域的,
      • 发送数据时 ,客户端->nginx->服务端
      • 返回数据时,服务端->nginx->客户端

    网络原理

    面试官:讲一讲三次握手四次挥手,为什么是三次握手四而不是两次握手?⭐⭐⭐⭐⭐

    • 客户端和服务端之间通过三次握手建立连接,四次挥手释放连接

    • 三次握手,客户端先向服务端发起一个SYN包,进入SYN_SENT状态,服务端收到SYN后,给客户端返回一个ACK+SYN包,表示已收到SYN,并进入SYN_RECEIVE状态,最后客户端再向服务端发送一个ACK包表示确认,双方进入establish状态。

      • 之所以是三次握手而不是两次,是因为如果只有两次,在服务端收到SYN后,向客户端返回一个ACK确认就进入establish状态,万一这个请求中间遇到网络情况而没有传给客户端,客户端一直是等待状态,后面服务端发送的信息客户端也接受不到了。
    • 四次挥手,首先客户端向服务端发送一个FIN包,进入FIN_WAIT1状态,服务端收到后,向客户端发送ACK确认包,进入CLOSE_WAIT状态,然后客户端收到ACK包后进入FIN_WAIT2状态,然后服务端再把自己剩余没传完的数据发送给客户端,发送完毕后在发送一个FIN+ACK包,进入LAST_ACK(最后确认)状态,客户端收到FIN+ACK包后,再向服务端发送ACK包,在等待两个周期后在关闭连接

      • 之所以等待两个周期是因为最后服务端发送的ACK包可能会丢失,如果不等待2个周期的话,服务端在没收收到ACK包之前,会不停的重复发送FIN包而不关闭,所以得等待两个周期

    面试官:HTTP的结构⭐⭐⭐⭐

    • 请求行 请求头 空行 请求体
      • 请求行包括 http版本号,url,请求方式
      • 响应行包括版本号,状态码,原因

    HTTP头都有哪些字段⭐⭐⭐⭐

    • 请求头
      • cache-control 是否使用缓存
      • Connection:keep-alive 与服务器的连接状态
      • Host 主机域
    • 返回头
      • cache-control
      • etag 唯一标识,缓存用的
      • last-modified最后修改时间

    面试官:说说你知道的状态码⭐⭐⭐⭐⭐

    • 2开头的表示成功
      • 一般见到的就是200
    • 3开头的表示重定向
      • 301永久重定向
      • 302临时重定向
      • 304表示可以在缓存中取数据(协商缓存)
    • 4开头表示客户端错误
      • 403跨域
      • 404请求资源不存在
    • 5开头表示服务端错误
      • 500

    网络OSI七层模型都有哪些?TCP是哪一层的⭐⭐⭐⭐

    • 七层模型
      • 应用层
      • 表示层
      • 会话层
      • 传输层
      • 网络层
      • 数据链路层
      • 物理层
    • TCP属于传输层

    面试官:http1.0和http1.1,还有http2有什么区别?⭐⭐⭐⭐

    • http0.9只能进行get请求
    • http1.0添加了POST,HEAD,OPTION,PUT,DELETE等
    • http1.1增加了长连接keep-alive,增加了host域,而且节约带宽
    • http2 多路复用,头部压缩,服务器推送

    面试官:https和http有什么区别,https的实现原理?⭐⭐⭐⭐⭐

    • http无状态无连接,而且是明文传输,不安全
    • https传输内容加密,身份验证,保证数据完整性
    • https实现原理⭐⭐⭐⭐⭐
      • 首先客户端向服务端发起一个随机值,以及一个加密算法
      • 服务端收到后返回一个协商好的加密算法,以及另一个随机值
      • 服务端在发送一个公钥CA
      • 客户端收到以后先验证CA是否有效,如果无效则报错弹窗,有过有效则进行下一步操作
      • 客户端使用之前的两个随机值和一个预主密钥组成一个会话密钥,在通过服务端传来的公钥加密把会话密钥发送给服务端
      • 服务端收到后使用私钥解密,得到两个随机值和预主密钥,然后组装成会话密钥
      • 客户端在向服务端发起一条信息,这条信息使用会话秘钥加密,用来验证服务端时候能收到加密的信息
      • 服务端收到信息后返回一个会话秘钥加密的信息
      • 都收到以后SSL层连接建立成功

    面试官:localStorage、SessionStorage、cookie、session 之间有什么区别⭐⭐⭐⭐⭐

    • localStorage
      • 生命周期:关闭浏览器后数据依然保留,除非手动清除,否则一直在
      • 作用域:相同浏览器的不同标签在同源情况下可以共享localStorage
    • sessionStorage
      • 生命周期:关闭浏览器或者标签后即失效
      • 作用域:只在当前标签可用,当前标签的iframe中且同源可以共享
    • cookie
      • 是保存在客户端的,一般由后端设置值,可以设置过期时间
      • 储存大小只有4K
      • 一般用来保存用户的信息的
      • 在http下cookie是明文传输的,较不安全
      • cookie属性有
        • http-only:不能被客户端更改访问,防止XSS攻击(保证cookie安全性的操作)
        • Secure:只允许在https下传输
        • Max-age: cookie生成后失效的秒数
        • expire: cookie的最长有效时间,若不设置则cookie生命期与会话期相同
    • session
      • session是保存在服务端的
      • session的运行依赖sessionId,而sessionId又保存在cookie中,所以如果禁用的cookie,session也是不能用的,不过硬要用也可以,可以把sessionId保存在URL中
      • session一般用来跟踪用户的状态
      • session 的安全性更高,保存在服务端,不过一般为使服务端性能更加,会考虑部分信息保存在cookie中

    localstorage存满了怎么办?⭐⭐⭐

    • 划分域名,各域名下的存储空间由各业务组统一规划使用
    • 跨页面传数据:考虑单页应用、采用url传输数据
    • 最后兜底方案:情调别人的存储

    怎么使用cookie保存用户信息⭐⭐⭐

    • document.cookie(“名字 = 数据;expire=时间”)

    怎么删除cookie⭐⭐⭐

    • 目前没有提供删除的操作,但是可以把它的Max-age设置为0,也就是立马失效,也就是删除了

    面试官:Get和Post的区别⭐⭐⭐⭐⭐

    https://www.zhihu.com/question/28586791

    • 冪等/不冪等(可缓存/不可缓存)
      • get请求是冪等的,所以get请求的数据是可以缓存的
      • 而post请求是不冪等的,查询查询对数据是有副作用的,是不可缓存的
    • 传参
      • get传参,参数是在url中的
        • 准确的说get传参也可以放到body中,只不过不推荐使用
      • post传参,参数是在请求体中
        • 准确的说post传参也可以放到url中,只不过不推荐使用
    • 安全性
      • get较不安全
      • post较为安全
      • 准确的说两者都不安全,都是明文传输的,在路过公网的时候都会被访问到,不管是url还是header还是body,都会被访问到,要想做到安全,就需要使用https
    • 参数长度
      • get参数长度有限,是较小的
        • 准确来说,get在url传参的时候是很小的
      • post传参长度不受限制
    • 发送数据
      • post传参发送两个请求包,一个是请求头,一个是请求体,请求头发送后服务器进行验证,要是验证通过的话就会给客户端发送一个100-continue的状态码,然后就会发送请求体
    • 字符编码
      • get在url上传输的时候只允许ASCII编码

    面试官:讲讲http缓存⭐⭐⭐⭐⭐

    https://www.jianshu.com/p/9c95db596df5

    • 缓存分为强缓存和协商缓存
    • 强缓存
      • 在浏览器加载资源时,先看看cache-control里的max-age,判断数据有没有过期,如果没有直接使用该缓存 ,有些用户可能会在没有过期的时候就点了刷新按钮,这个时候浏览器就回去请求服务端,要想避免这样做,可以在cache-control里面加一个immutable.
      • public
        • 允许客户端和虚拟服务器缓存该资源,cache-control中的一个属性
      • private
        • 只允许客户端缓存该资源
      • no-storage
        • 不允许强缓存,可以协商缓存
      • no-cache
        • 不允许缓存
    • 协商缓存
      • 浏览器加载资源时,没有命中强缓存,这时候就去请求服务器,去请求服务器的时候,会带着两个参数,一个是If-None-Match,也就是响应头中的etag属性,每个文件对应一个etag;另一个参数是If-Modified-Since,也就是响应头中的Last-Modified属性,带着这两个参数去检验缓存是否真的过期,如果没有过期,则服务器会给浏览器返回一个304状态码,表示缓存没有过期,可以使用旧缓存。
      • etag的作用
        • 有时候编辑了文件,但是没有修改,但是last-modified属性的时间就会改变,导致服务器会重新发送资源,但是etag的出现就完美的避免了这个问题,他是文件的唯一标识

    缓存位置:

    • 内存缓存Memory-Cache
    • 离线缓存Service-Worker
    • 磁盘缓存Disk-Cache
    • 推送缓存Push-Cache

    面试官:tcpudp有什么区别⭐⭐⭐⭐⭐

    • 连接方面

      • tcp面向连接,udp不需要连接
        • tcp需要三次握手四次挥手请求连接
    • 可靠性

      • tcp是可靠传输;一旦传输过程中丢包的话会进行重传
      • udp是不可靠传输,但会最大努力交付
    • 工作效率

      • UDP实时性高,比TCP工作效率高
        • 因为不需要建立连接,更不需要复杂的握手挥手以及复杂的算法,也没有重传机制
    • 是否支持多对多

      • TCP是点对点的
      • UDP支持一对一,一对多,多对多
    • 首部大小

      • tcp首部占20字节
      • udp首部占8字节

    面试官:从浏览器输入url后都经历了什么⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐具重要!

    • 先进行DNS域名解析,先查看本地hosts文件,查看有没有当前域名对应的ip地址,若有直接发起请求,没有的话会在本地域名服务器去查找,该查找属于递归查找,如果本地域名服务器没查找到,会从根域名服务器查找,该过程属于迭代查找,根域名会告诉你从哪个与服务器查找,最后查找到对应的ip地址后把对应规则保存到本地的hosts文件中。
    • 如果想加速以上及之后的http请求过程的话可以使用缓存服务器CDN,CDN过程如下:
      • 用户输入url地址后,本地DNS会解析url地址,不过会把最终解析权交给CNAME指向的CDN的DNS服务器
      • CDN的DNS服务器会返回给浏览器一个全局负载均衡IP
      • 用户会根据全局负载均衡IP去请求全局负载均衡服务器
      • 全局负载均衡服务器会根据用户的IP地址,url地址,会告诉用户一个区域负载均衡设备,让用户去请求它。
      • 区域负载均衡服务器会为用户选择一个离用户较近的最优的缓存服务器,并把ip地址给到用户
      • 用户想缓存服务器发送请求,如果请求不到想要的资源的话,会一层层向上一级查找,知道查找到为止。
    • 进行http请求,三次握手四次挥手建立断开连接
    • 服务器处理,可能返回304也可能返回200
      • 返回304说明客户端缓存可用,直接使用客户端缓存即可,该过程属于协商缓存
      • 返回200的话会同时返回对应的数据
    • 客户端自上而下执行代码
      • 其中遇到CSS加载的时候,CSS不会阻塞DOM树的解析,但是会阻塞DOM树的渲染,并且CSS会阻塞下面的JS的执行
      • 然后是JS加载,JS加载会影响DOM的解析,之所以会影响,是因为JS可能会删除添加节点,如果先解析后加载的话,DOM树还得重新解析,性能比较差。如果不想阻塞DOM树的解析的话,可以给script添加一个defer或者async的标签。
        • defer:不会阻塞DOM解析,等DOM解析完之后在运行,在DOMContentloaed之前
        • async: 不会阻塞DOM解析,等该资源下载完成之后立刻运行
      • 进行DOM渲染和Render树渲染
        • 获取html并解析为Dom树
        • 解析css并形成一个cssom(css树)
        • 将cssom和dom合并成渲染树(render树)
        • 进行布局(layout)
        • 进行绘制(painting)
        • 回流重绘
          • 回流必将引起重绘,重绘不一定引起回流

    滑动窗口和拥塞窗口有什么区别⭐⭐⭐

    解析TCP之滑动窗口(动画演示)
    以动画的形式解释滑动窗口,

    • 滑动窗口
      • 发送窗口永远小于或等于接收窗口,发送窗口的大小取决于接收窗口的大小
      • 控制流量来保证TCP的可靠传输(不控制流量的话可能会溢出)
      • 发送方的数据分为
        • 1已发送,接收到ACK的
        • 2已发送,未接收到ACK的
        • 3未发送,但允许发送的
        • 4未发送,但不允许发送的
        • 2和3表示发送窗口
      • 接收方
        • 1.已接收
        • 2.未接受但准备接受
        • 3.未接受不准备接受
    • 拥塞窗口
      • 防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
      • 是一个全局性的过程
      • 方法
        • 慢开始、拥塞避免、快重传、快恢复

    什么是CDN?⭐⭐⭐⭐

    关于 cdn、回源等问题一网打尽

    1.首先访问本地的 DNS ,如果没有命中,继续递归或者迭代查找,直到命中拿到对应的 IP 地址。

    2.拿到对应的 IP 地址之后服务器端发送请求到目的地址。注意这里返回的不直接是 cdn 服务器的 IP 地址,而是全局负载均衡系统的 IP 地址

    4.全局负载均衡系统会根据客户端的 IP地址和请求的 url 和相应的区域负载均衡系统通信

    5.区域负载均衡系统拿着这两个东西获取距离客户端最近且有相应资源的cdn 缓存服务器的地址,返回给全局负载均衡系统

    6.全局负载均衡系统返回确定的 cdn 缓存服务器的地址给客户端。

    7.客户端请求缓存服务器上的文件

    什么是xss?什么是csrf?⭐⭐⭐⭐⭐

    • xss脚本注入
      • 不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本(可能是js、hmtl代码块等)。
      • 防御
        • 编码:对用户输入的数据进行HTML Entity 编码。把字符转换成 转义字符。Encode的作用是将$var等一些字符进行转化,使得浏览器在最终输出结果上是一样的。
        • 过滤:移除用户输入的和事件相关的属性。
    • csrf跨域请求伪造
      • 在未退出A网站的前提下访问B,B使用A的cookie去访问服务器
      • 防御:token,每次用户提交表单时需要带上token(伪造者访问不到),如果token不合法,则服务器拒绝请求

    OWASP top10 (10项最严重的Web应用程序安全风险列表)都有哪些?⭐⭐⭐

    • SQL注入

      • 在输入框里输入sql命令
    • 失效的身份验证

      • 拿到别人的cookie来向服务端发起请求,就可以做到登陆的目的
    • 敏感数据泄露

      • 明文传输状态下可能被抓包拦截,这时候就造成数据泄露
        • 想做到抓包,比如在网吧,共享一个猫上网,这时候抓包就可行,方法网上一搜一大把
      • 不过此风险大部分网站都能得到很好的解决,https或者md5加密都可以
    • XML 外部实体

    • 失效的访问控制

    • 安全配置错误

    • XSS

    • 不安全的反序列化

    • 使用含有已知漏洞的组件

    • 不足的日志记录和监控

    怎么样?计算机网络是不是没有想象中的那么难,如果你没看过瘾的话,推荐你这篇文章:【长文】前端需要了解的计算机网络知识
    是不是得感激我一下【手动滑稽】

     

    谢谢

    面试官:什么是回流 什么是重绘?⭐⭐⭐⭐⭐

    • 回流
      • render树中一部分或全部元素需要改变尺寸、布局、或着需要隐藏而需要重新构建,这个过程叫做回流
      • 回流必将引起重绘
    • 重绘
      • render树中一部分元素改变,而不影响布局的,只影响外观的,比如颜色。该过程叫做重绘
    • 页面至少经历一次回流和重绘(第一次加载的时候)

    杂项

    事件冒泡和事件捕捉有什么区别⭐⭐⭐⭐⭐

    • 事件冒泡
      • 在addEventListener中的第三属性设置为false(默认)
      • 从下至上(儿子至祖宗)执行
    • 事件捕捉
      • 在addEventListener中的第三属性设置为true
      • 从上至下(祖宗到儿子)执行

    什么是防抖?什么是节流?手写一个⭐⭐⭐⭐⭐

    • 防抖
      • n秒后在执行该事件,若在n秒内被重复触发,则重新计时
    • 节流
      • n秒内只运行一次,若在n秒内重复触发,只有一次生效
    // ---------------------------------------------------------防抖函数
        function debounce(func, delay) {
          let timeout
          return function () {
            let arg = arguments
            if (timeout) clearTimeout(timeout)
            timeout = setTimeout(() => {
              func(arg)
            }, delay);
          }
        }
     
        // ---------------------------------------------------------立即执行防抖函数
        function debounce2(fn, delay) {
          let timer
     
          return function () {
            let args = arguments
            if (timer) clearTimeout(timer)
     
     
            let callNow = !timer
            timer = setTimeout(() => {
              timer = null
            }, delay);
            if (callNow) { fn(args) }
          }
        }
        // ---------------------------------------------------------立即执行防抖函数+普通防抖
        function debounce3(fn, delay, immediate) {
          let timer
     
          return function () {
            let args = arguments
            let _this = this
            if (timer) clearTimeout(timer)
     
            if (immediate) {
              let callNow = !timer
              timer = setTimeout(() => {
                timer = null
              }, delay);
     
              if (callNow) { fn.apply(_this, args) }
            } else {
              timeout = setTimeout(() => {
                func.apply(_this, arguments)
              }, delay);
            }
          }
        }
     
        // ---------------------------------------------------------节流 ,时间戳版
     
        function throttle(fn, wait) {
     
          let previous = 0
          return function () {
            let now = Date.now()
            let _this = this
            let args = arguments
            if (now - previous > wait) {
              fn.apply(_this, arguments)
              previous = now
            }
          }
        }
     
        // ---------------------------------------------------------节流 ,定时器版
        function throttle2(fn, wait) {
          let timer
          return function () {
            let _this = this
            let args = arguments
            if (!timer) {
              timer = setTimeout(() => {
                timer = null
                fn.apply(_this, arguments)
              }, wait);
            }
          }
        }
    

     

     

    函数柯里化原理⭐⭐⭐⭐⭐

    function add() {
          var args = Array.prototype.slice.call(arguments)
     
          var adder = function () {
            args.push(...arguments)
            return adder
          }
     
          adder.toString = function () {
            return args.reduce((prev, curr) => {
              return prev + curr
            }, 0)
          }
     
          return adder
        }
     
        let a = add(1, 2, 3)
        let b = add(1)(2)(3)
        console.log(a)
        console.log(b)
        console.log(add(1, 2)(3));
        console.log(Function.toString)
    
     

    什么是requestAnimationFrame?⭐⭐⭐⭐

    • requestAnimationFrame请求数据帧可以用做动画执行

    • 可以自己决定什么时机调用该回调函数

    • 能保证每次频幕刷新的时候只被执行一次

    • 页面被隐藏或者最小化的时候暂停执行,返回窗口继续执行,有效节省CPU

    • var s = 0
          function f() {
            s++
            console.log(s);
            if (s < 999) {
              window.requestAnimationFrame(f)
            }
          }
          window.requestAnimationFrame(f)
      

       

    js常见的设计模式⭐⭐⭐⭐⭐

    • 单例模式、工厂模式、构造函数模式、发布订阅者模式、迭代器模式、代理模式

    • 单例模式

      • 不管创建多少个对象都只有一个实例

      • var Single = (function () {
              var instance = null
              function Single(name) {
                this.name = name
              }
              return function (name) {
                if (!instance) {
                  instance = new Single()
                }
                return instance
              }
            })()
         
            var oA = new Single('hi')
            var oB = new Single('hello')
            console.log(oA);
            console.log(oB);
            console.log(oB === oA);
        

         

    • 工厂模式

      • 代替new创建一个对象,且这个对象想工厂制作一样,批量制作属性相同的实例对象(指向不同)

      • function Animal(o) {
              var instance = new Object()
              instance.name = o.name
              instance.age = o.age
              instance.getAnimal = function () {
                return "name:" + instance.name + " age:" + instance.age
              }
              return instance
            }
         
            var cat = Animal({name:"cat", age:3})
            console.log(cat);
        

         

    • 构造函数模式

    • 发布订阅者模式

    • class Watcher {
            // name模拟使用属性的地方
            constructor(name, cb) {
              this.name = name
              this.cb = cb
            }
            update() {//更新
              console.log(this.name + "更新了");
              this.cb() //做出更新回调
            }
          }
       
          class Dep {//依赖收集器
            constructor() {
              this.subs = []
            }
            addSubs(watcher) {
              this.subs.push(watcher)
            }
            notify() {//通知每一个观察者做出更新
              this.subs.forEach(w => {
                w.update()
              });
            }
          }
       
          // 假如现在用到age的有三个地方
          var w1 = new Watcher("我{{age}}了", () => { console.log("更新age"); })
          var w2 = new Watcher("v-model:age", () => { console.log("更新age"); })
          var w3 = new Watcher("I am {{age}} years old", () => { console.log("更新age"); })
       
          var dep = new Dep()
          dep.addSubs(w1)
          dep.addSubs(w2)
          dep.addSubs(w3)
       
       
          // 在Object.defineProperty 中的 set中运行
          dep.notify()
      

       

    • 代理模式

    • 迭代器模式

    JS性能优化的方式⭐⭐⭐⭐⭐

    • 垃圾回收
    • 闭包中的对象清楚
    • 防抖节流
    • 分批加载(setInterval,加载10000个节点)
    • 事件委托
    • 少用with
    • requestAnimationFrame的使用
    • script标签中的defer和async
    • CDN

    Vue

    Vue双向绑定

    数据劫持: vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调

    阐述一下你所理解的MVVM响应式原理⭐⭐⭐⭐⭐

    vue是采用数据劫持配合发布者-订阅者的模式的方式,通过Object.defineProperty()来劫持各个属性的getter和setter,在数据变动时,发布消息给依赖收集器(dep中的subs),去通知(notify)观察者,做出对应的回调函数,去更新视图

    MVVM作为绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer,Compile之间的通信桥路,达到数据变化=>视图更新;视图交互变化=>数据model变更的双向绑定效果。

    杂乱笔记

    • data中每一个数据都绑定一个Dep,这个Dep中都存有所有用到该数据的观察者

    • 当数据改变时,发布消息给dep(依赖收集器),去通知每一个观察者。做出对应的回调函数

    • const dep = new Dep()
          // 劫持并监听所有属性
          Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: false,
            get() {
              // 订阅数据变化时,在Dep中添加观察者
              Dep.target && dep.addSub(Dep.target)
              return value
            },
            set: (newVal) => {
              if (newVal !== value) {
                this.observe(newVal)
                value = newVal
              }
              // 告诉Dep通知变化
              dep.notify()
       
            },
          })

       

    面试官:说说vue的生命周期⭐⭐⭐⭐⭐

    • beforeCreate
      • 创建之前,此时还没有data和Method
    • Created
      • 创建完成,此时data和Method可以使用了
      • 在Created之后beforeMount之前如果没有el选项的话那么此时生命周期结束,停止编译,如果有则继续
    • beforeMount
      • 在渲染之前
    • mounted
      • 页面已经渲染完成,并且vm实例中已经添加完$el了,已经替换掉那些DOM元素了(双括号中的变量),这个时候可以操作DOM了(但是是获取不了元素的高度等属性的,如果想要获取,需要使用nextTick())
    • beforeUpdate
      • data改变后,对应的组件重新渲染之前
    • updated
      • data改变后,对应的组件重新渲染完成
    • beforeDestory
      • 在实例销毁之前,此时实例仍然可以使用
    • destoryed
      • 实例销毁后

    面试官:vue中父子组件的生命周期⭐⭐⭐⭐⭐

    • 父子组件的生命周期是一个嵌套的过程
    • 渲染的过程
      • beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
    • 子组件更新过程
      • beforeUpdate->子beforeUpdate->子updated->父updated
    • 父组件更新过程
      • beforeUpdate->父updated
    • 销毁过程
      • beforeDestroy->子beforeDestroy->子destroyed->父destroyed

    Vue中的nextTick⭐⭐⭐⭐⭐

    • nextTick

      • 解释
        • nextTick:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
      • 应用
        • 想要在Vue生命周期函数中的created()操作DOM可以使用Vue.nextTick()回调函数
        • 在数据改变后要执行的操作,而这个操作需要等数据改变后而改变DOM结构的时候才进行操作,需要用到nextTick

    面试官:computed和watch的区别⭐⭐⭐⭐⭐

    • computed
      • 计算属性,依赖其他属性,当其他属性改变的时候下一次获取computed值时也会改变,computed的值会有缓存
    • watch
      • 类似于数据改变后的回调
      • 如果想深度监听的话,后面加一个deep:true
      • 如果想监听完立马运行的话,后面加一个immediate:true

    面试官:Vue优化方式⭐⭐⭐⭐⭐

    • v-if 和v-show

    • 使用Object.freeze()方式冻结data中的属性,从而阻止数据劫持

    • 组件销毁的时候会断开所有与实例联系,但是除了addEventListener,所以当一个组件销毁的时候需要手动去removeEventListener

    • 图片懒加载

    • 路由懒加载

    • 为减少重新渲染和创建dom节点的时间,采用虚拟dom

    面试官:Vue-router的模式⭐⭐⭐⭐⭐

    • hash模式
      • 利用onhashchange事件实现前端路由,利用url中的hash来模拟一个hash,以保证url改变时,页面不会重新加载。
    • history模式
      • 利用pushstate和replacestate来将url替换但不刷新,但是有一个致命点就是,一旦刷新的话,就会可能404,因为没有当前的真正路径,要想解决这一问题需要后端配合,将不存在的路径重定向到入口文件。

    面试官:MVC与MVVM有什么区别⭐⭐⭐⭐⭐

    哎呀呀,这个要参考的就多了。mvc和mvvm的区别基于Vue实现一个简易MVVM不好意思!耽误你的十分钟,让MVVM原理还给你

    • MVC
      • Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据
      • View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
      • Controller(控制器)是应用程序中处理用户交互的部分
        • 通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据

    diff算法⭐⭐⭐⭐⭐

    • diff算法是指对新旧虚拟节点进行对比,并返回一个patch对象,用来存储两个节点不同的地方,最后利用patch记录的消息局部更新DOM

    虚拟DOM的优缺点⭐⭐⭐⭐⭐

    • 缺点
      • 首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢
    • 优点
      • 减少了dom操作,减少了回流与重绘
      • 保证性能的下限,虽说性能不是最佳,但是它具备局部更新的能力,所以大部分时候还是比正常的DOM性能高很多的

    Vue的Key的作用 ⭐⭐⭐⭐

    • key
      • key主要用在虚拟Dom算法中,每个虚拟节点VNode有一个唯一标识Key,通过对比新旧节点的key来判断节点是否改变,用key就可以大大提高渲染效率,这个key类似于缓存中的etag。

    Vue组件之间的通信方式⭐⭐⭐⭐⭐

    • 子组件设置props + 父组件设置v-bind:/:

      • 父传子
    • 子组件的$emit + 父组件设置v-on/@

      • 子传父
    • 任意组件通信,新建一个空的全局Vue对象,利用 e m i t 发 送 , emit发送, emit发送,on接收

      • 传说中的$bus

      • 任意组件

      • Vue.prototype.Event=new Vue();
        	
         
            Event.$emit(事件名,数据);
            Event.$on(事件名,data => {});
        

         

    • Vuex

      • 里面的属性有:
        • state
          • 存储数据的
          • 获取数据最好推荐使用getters
          • 硬要使用的话可以用MapState, 先引用,放在compute中...mapState(['方法名','方法名'])
        • getters
          • 获取数据的
          • this.$store.getters.xxx
          • 也可使用mapGetters 先引用,放在compute中,...mapGetters(['方法名','方法名'])
        • mutations
          • 同步操作数据的
          • this.$store.commit(“方法名”,数据)
          • 也可使用mapMutations ,使用方法和以上一样
        • actions
          • 异步操作数据的
          • this.$store.dispatch(“方法名”,数据)
          • 也可使用mapActions ,使用方法和以上一样
        • modules
          • 板块,里面可以放多个vuex
    • 父组件通过v-bind:/:传值,子组件通过this.$attrs获取

      • 父传子
      • 当子组件没有设置props的时候可以使用
      • this.$attrs获取到的是一个对象(所有父组件传过来的集合)
    • 祖先组件使用provide提供数据,子孙组件通过inject注入数据

    • p a r e n t / parent/ parent/children

    • refs—$ref

    • 还有一个,这个网上没有,我自己认为的,我觉得挺对的,slot-scope,本身父组件使用slot插槽是无法获取子组件的数据的,但是使用了slot-scope就可以获取到子组件的数据(拥有了子组件的作用域)

    Vue-router有哪几种钩子函数⭐⭐⭐⭐⭐

    • beforeEach
      • 参数有
        • to(Route路由对象)
        • from(Route路由对象)
        • next(function函数) 一定要调用才能进行下一步
    • afterEach
    • beforeRouterLeave

    Webpack

    webpack常用的几个对象及解释⭐⭐⭐⭐

    • entry 入口文件

    • output 输出文件

      • 一般配合node的path模块使用

        // 入口文件
            entry:"./src/index.js",
            output:{
                // 输出文件名称
                filename:"bundle.js",
                // 输出的路径(绝对路径)
                path:path.resolve(__dirname,"dist") //利用node模块的path 绝对路径
            },
            // 设置模式
            mode:"development"
        

         

    • mode 设计模式

    • module(loader)

      • 里面有一个rules数组对某种格式的文件进行转换处理(转换规则)

      • use数组解析顺序是从下到上逆序执行的

      • module:{
               // 对某种格式的文件进行转换处理(转换规则)
               rules:[
                   {
                       // 用到正则表达式
                       test:/\.css$/,      //后缀名为css格式的文件
                       use:[
                           // use数组解析顺序是从下到上逆序执行的
                           // 先用css-loader 再用style-loader
                           // 将js的样式内容插入到style标签里
                           "style-loader",
                           // 将css文件转换为js
                           "css-loader"
                       ]
                   }
               ]
           }
         
        // -----------------------------------------------------vue的
        module.exports={
            module:{
                rules:[
                    {
                        test: /\.vue$/,
                        use:["vue-loader"]
                    }
                ]
            }
        }
        

         

    • plugin

      • 插件配置

      • const uglifyJsPlugin = reqiure('uglifyjs-webpack-plugin')
         
        module.exports={
        	plugin:[
        		new uglifyJsPlugin()	//丑化
        	]
        }
        

         

    • devServer

      • 热更新

      • devServer:{
                // 项目构建路径
                contentBase:path.resolve(__dirname,"dist"),
                // 启动gzip亚索
                compress:true,
                // 设置端口号
                port:2020,
                // 自动打开浏览器:否
                open:false,
                //页面实时刷新(实时监听)
                inline:true
            }
        

         

    • resolve

      • 配置路径规则

      • alias 别名

      • module.exports= {
        	resolve:{
        		//如果导入的时候不想写后缀名可以在resolve中定义extensions
        		extensions:['.js','.css','.vue']
        		//alias:别名
        		alias:{
        			//导入以vue结尾的文件时,会去寻找vue.esm.js文件
        			'vue$':"vue/dist/vue.esm.js"
        		}
        	}
        }
        

         

    • babel(ES6转ES5)

      • 下载插件babel-loader,在module(loader)中配置

    loader和plugin的区别是什么?⭐⭐⭐

    • loader
      • loader是用来解析非js文件的,因为Webpack原生只能解析js文件,如果想把那些文件一并打包的话,就需要用到loader,loader使webpack具有了解析非js文件的能力
    • plugin
      • 用来给webpack扩展功能的,可以加载许多插件

    CSS/HTML

    flex布局⭐⭐⭐⭐⭐

    这个我就不例举了,看看阮一峰老师的文章叭!Flex 布局教程

    grid布局⭐⭐⭐⭐

    同样是阮一峰老师的,CSS Grid 网格布局教程

    常见的行内元素和块级元素都有哪些?⭐⭐⭐⭐⭐

    • 行内元素 inline
      • 不能设置宽高,不能自动换行
      • span、input、img、textarea、label、select
    • 块级元素block
      • 可以设置宽高,会自动换行
      • p、h1/h2/h3/h4/h5、div、ul、li、table
    • inline-block
      • 可以设置宽高,会自动换行

    请说明px,em,rem,vw,vh,rpx等单位的特性⭐⭐⭐⭐⭐

    • px
      • 像素
    • em
      • 当前元素的字体大小
    • rem
      • 根元素字体大小
    • vw
      • 100vw是总宽度
    • vh
      • 100vh是总高度
    • rpx
      • 750rpx是总宽度

    常见的替换元素和非替换元素?⭐⭐

    • 替换元素
      • 是指若标签的属性可以改变标签的显示方式就是替换元素,比如input的type属性不同会有不同的展现,img的src等
      • img、input、iframe
    • 非替换元素
      • div、span、p

    first-of-type和first-child有什么区别⭐⭐⭐⭐

    • first-of-type
      • 匹配的是从第一个子元素开始数,匹配到的那个的第一个元素
    • first-child
      • 必须是第一个子元素

    doctype标签和meta标签⭐⭐⭐⭐⭐

    • doctype
      • 告诉浏览器以什么样的文档规范解析文档
      • 标准模式和兼容模式
        • 标准模式 ->正常,排版和js运作模式都是以最高标准运行
        • 兼容模式->非正常

    script标签中defer和async都表示了什么⭐⭐⭐⭐⭐

    • 众所周知script会阻塞页面的加载,如果我们要是引用外部js,假如这个外部js请求很久的话就难免出现空白页问题,好在官方为我们提供了defer和async

    • defer

    •  
      <script src="d.js" defer></script>
      <script src="e.js" defer></script>
      
      • 不会阻止页面解析,并行下载对应的js文件

      • 下载完之后不会执行

      • 等所有其他脚本加载完之后,在DOMContentLoaded事件之前执行对应d.jse.js

    • async

    • <script src="b.js" async></script>
      <script src="c.js" async></script>
      
      • 不会阻止DOM解析,并行下载对应的js文件

      • 下载完之后立即执行

    • 补充DOMContentLoaded事件

      • 是等HTML文档完全加载完和解析完之后运行的事件
      • load事件之前。
      • 不用等样式表、图像等完成加载

    什么是BFC?⭐⭐⭐⭐⭐

    • BFC是一个独立渲染区域,它丝毫不会影响到外部元素
    • BFC特性
      • 同一个BFC下margin会重叠
      • 计算BFC高度时会算上浮动元素
      • BFC不会影响到外部元素
      • BFC内部元素是垂直排列的
      • BFC区域不会与float元素重叠
    • 如何创建BFC
      • position设为absolute或者fixed
      • float不为none
      • overflow设置为hidden
      • display设置为inline-block或者inline-table或flex

    如何清除浮动⭐⭐⭐⭐⭐

    • 额外标签clear:both

      • <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
            <style>
            .fahter{
                width: 400px;
                border: 1px solid deeppink;
            }
            .big{
                width: 200px;
                height: 200px;
                background: darkorange;
                float: left;
            }
            .small{
                width: 120px;
                height: 120px;
                background: darkmagenta;
                float: left;
            }
         
            .clear{
                clear:both;
            }
            </style>
        </head>
        <body>
            <div class="fahter">
                <div class="big">big</div>
                <div class="small">small</div>
                <div class="clear">额外标签法</div>
            </div>
        </body>
        

         

    • 利用BFC

      • overflow:hidden

      • .fahter{
                width: 400px;
                border: 1px solid deeppink;
                overflow: hidden;
            }
        

         

    • 使用after(推荐)

    • <style>
          .clearfix:after{/*伪元素是行内元素 正常浏览器清除浮动方法*/
              content: "";
              display: block;
              height: 0;
              clear:both;
              visibility: hidden;
          }
          .clearfix{
              *zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/
          }
      </style>
      <body>
          <div class="fahter clearfix">
              <div class="big">big</div>
              <div class="small">small</div>
              <!--<div class="clear">额外标签法</div>-->
          </div>
      

       

    什么是DOM事件流?什么是事件委托⭐⭐⭐⭐⭐

    • DOM事件流
      • 分为三个阶段
        • 捕获阶段
        • 目标阶段
        • 冒泡阶段
      • 在addeventListener()的第三个参数(useCapture)设为true,就会在捕获阶段运行,默认是false冒泡
    • 事件委托
      • 利用冒泡原理(子向父一层层穿透),把事件绑定到父元素中,以实现事件委托

    link标签和import标签的区别⭐⭐⭐⭐

    • link属于html,而@import属于css
    • 页面被加载时,link会同时被加载,而@import引用的css会等到页面加载结束后加载。
    • link是html标签,因此没有兼容性,而@import只有IE5以上才能识别。
    • link方式样式的权重高于@import的。

    算法

    这里推荐一个排序算法的动画网站,应该是一个国外团队做的,Sorting Algorithms

    冒泡算法排序⭐⭐⭐⭐⭐

    // 冒泡排序
        /* 1.比较相邻的两个元素,如果前一个比后一个大,则交换位置。
       2.第一轮的时候最后一个元素应该是最大的一个。
       3.按照步骤一的方法进行相邻两个元素的比较,这个时候由于最后一个元素已经是最大的了,所以最后一个元素不用比较。 */
        function bubbleSort(arr) {
          for (var i = 0; i < arr.length; i++) {
            for (var j = 0; j < arr.length; j++) {
              if (arr[j] > arr[j + 1]) {
                var temp = arr[j]
                arr[j] = arr[j + 1]
                arr[j + 1] = temp
              }
            }
          }
        }
     
        var Arr = [3, 5, 74, 64, 64, 3, 1, 8, 3, 49, 16, 161, 9, 4]
        console.log(Arr, "before");
        bubbleSort(Arr)
        console.log(Arr, "after");
    
    
     

    快速排序⭐⭐⭐⭐⭐

    /*
        快速排序是对冒泡排序的一种改进,第一趟排序时将数据分成两部分,一部分比另一部分的所有数据都要小。
        然后递归调用,在两边都实行快速排序。  
        */
        
        function quickSort(arr) {
          if (arr.length <= 1) {
            return arr
          }
          var middle = Math.floor(arr.length / 2)
          var middleData = arr.splice(middle, 1)[0]
     
          var left = []
          var right = []
          
          for (var i = 0; i < arr.length; i++) {
            if (arr[i] < middleData) {
              left.push(arr[i])
            } else {
              right.push(arr[i])
            }
          }
     
          return quickSort(left).concat([middleData], quickSort(right))
        }
     
        var Arr = [3, 5, 74, 64, 64, 3, 1, 8, 3, 49, 16, 161, 9, 4]
        console.log(Arr, "before");
        var newArr = quickSort(Arr)
        console.log(newArr, "after");
    
     

    插入排序⭐⭐⭐⭐

    function insertSort(arr) {
          // 默认第一个排好序了
          for (var i = 1; i < arr.length; i++) {
            // 如果后面的小于前面的直接把后面的插到前边正确的位置
            if (arr[i] < arr[i - 1]) {
              var el = arr[i]
              arr[i] = arr[i - 1]
              var j = i - 1
              while (j >= 0 && arr[j] > el) {
                arr[j+1] = arr[j]
                j--
              }
              arr[j+1] = el
            }
          }
        }
     
        var Arr = [3, 5, 74, 64, 64, 3, 1, 8, 3, 49, 16, 161, 9, 4]
        console.log(Arr, "before");
        insertSort(Arr)
        console.log(Arr, "after");
    
     

    是否回文⭐⭐⭐⭐⭐

    function isHuiWen(str) {
          return str == str.split("").reverse().join("")
        }
     
        console.log(isHuiWen("mnm")); 
    
     

    正则表达式,千分位分隔符⭐⭐⭐⭐

    function thousand(num) {
     
          return (num+"").replace(/\d(?=(\d{3})+$)/g, "$&,")
        }
        console.log(thousand(123456789));
     

    斐波那契数列⭐⭐⭐⭐⭐

    // num1前一项
        // num2当前项
        function fb(n, num1 = 1, num2 = 1) {
          if(n == 0) return 0
          if (n <= 2) {
            return num2
          } else {
            return fb(n - 1, num2, num1 + num2)
          }
        }
     

    数组去重的方式⭐⭐⭐⭐⭐

    var arr = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]
     
        // 最low1
        let newArr2 = []
        for (let i = 0; i < arr.length; i++) {
          if (!newArr2.includes(arr[i])) {
            newArr2.push(arr[i])
          }
        }
        console.log(newArr2);
        // 最low2
        let arr2 = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]
        for (let i = 0; i < arr2.length; i++) {
          var item = arr2[i]
          for (let j = i + 1; j < arr2.length; j++) {
            var compare = arr2[j];
            if (compare === item) {
              arr2.splice(j, 1)
              j--
            }
          }
        }
        console.log(arr2);
     
     
        // 基于对象去重
        let arr3 = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]
        let obj = {}
        for (let i = 0; i < arr3.length; i++) {
     
          let item = arr3[i]
          if (obj[item]) {
            arr3[i] = arr3[arr3.length - 1]
            arr3.length--
            i--
            continue;
          }
          obj[item] = item
     
        }
        console.log(arr3);
        console.log(obj);
     
        // 利用Set
        let newArr1 = new Set(arr)
        console.log([...newArr1]);
     
     
        let arr4 = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2]
     
        //利用reduce
        newArr4 = arr4.reduce((prev, curr) => prev.includes(curr)? prev : [...prev,curr],[])
        console.log(newArr4);
        console.log(document);
    
     

    git

    git的常用命令⭐⭐⭐⭐⭐

    • commit之后撤回
      • git reset soft HEAD^
    • 分支
      • git branch xx 创建分支
      • git checkout xx切换分支
    • 添加
      • git add .
      • git push
      • git commit -m

     

    在这里插入图片描述

    git常用命令与常见面试题总结

    震惊!你竟然看完了,看来你距离大神就差一点点了!

     

    在这里插入图片描述
    在这里插入图片描述

    ok,今天的文章就到这里了。
    • 如果你觉得文章不错的话,可以收藏点赞,也可以关注上我,今后我可能会根据一些大公司的面试题进行在总结。
    • 如果你觉得文章特别水的话
      在这里插入图片描述

    转载于:https://blog.csdn.net/qq_40442753/article/details/113410172 

    展开全文
  • 各公司秋招很快就开始了,最近在准备面试的东西,干脆将发现的各类面试题整理一下共享出来,大部分面试题是没有标准答案的,我给出的答案也是仅供参考,如果有更好的解答欢迎在评论区留言
  • 点进来之后你的噩梦就要来了,接下来你要面对上百道面试题,那么,如果你—— 是个小白菜: 推荐使用2~3周的时间来消化接下来的面试题, 遇到不会的没听说过名词请立刻去搜; 文章中只是简答,如果想要详细了解的话...

    前言

    点进来之后你的噩梦就要来了,接下来你要面对上百道面试题,那么,如果你——

    是个小白菜:

    内容有点多哦~~
    推荐使用2~3周的时间来消化接下来的面试题,
    遇到不会的没听说过名词请立刻去搜;
    文章中只是简答,如果想要详细了解的话还需要你自觉去搜索
    如果你是个大神:
    好叭先给您拜个早年,大哥大嫂过年好。
    请温柔点黑我。
    顺便,如果有错误的地方请各位一定要指出,免得误导更多人。
    接下来的题我会根据重点程度使用⭐来标记,⭐越多标明越重点,满星是5颗星
    ok,你准备好了吗?咱们开始吧!

     

    JS
    数据类型
    面试官:JavaScript中什么是基本数据类型什么是引用数据类型?以及各个数据类型是如何存储的?⭐⭐⭐⭐⭐

    答:
    基本数据类型有

    Number
    String
    Boolean
    Null
    U

    展开全文
  • 由于疫情原因,原本每年的“金三银四”仿佛消失,随之而来的是找工作的压力,这里给要面试的小伙伴们总结了到目前为止我遇到的前端面试题,仅供参考哦,第一次写博客,如有错误之处,还请指出。 一. vue方面 1.vue-...
  • 2021年最新Web前端面试题精选大全及答案_HanXiaoXi_yeal的博客-CSDN博客_前端面试题2021及答案.html
  • 2021前端面试题汇总》主要介绍了js基础到入门、css和常用的web框架的一些常用面试题目。学完这个题库,把此题库都理解透彻应对各家企业面试完全没有问题。
  • 点进来之后你的噩梦就要来了,接下来你要面对上百道面试题,那么,如果你—— 是个小白菜: 推荐使用2~3周的时间来消化接下来的面试题, 遇到不会的没听说过名词请立刻去搜; 文章中只是简答,如果想要详细...

    转发来自:https://blog.csdn.net/qq_33277654/article/details/112758362

    点进来之后你的噩梦就要来了,接下来你要面对上百道面试题,那么,如果你——

    • 是个小白菜:
      • 推荐使用2~3周的时间来消化接下来的面试题,
      • 遇到不会的没听说过名词请立刻去搜;
      • 文章中只是简答,如果想要详细了解的话还需要你自觉去搜索
    • 如果你是个大神:
      • 好叭先给您拜个早年,大哥大嫂过年好。
      • 请温柔点黑我。

    顺便,如果有错误的地方请各位一定要指出,免得误导更多人。
    接下来的题我会根据重点程度使用⭐来标记,⭐越多标明越重点,满星是5颗星
    ok,你准备好了吗?咱们开始吧!

    在这里插入图片描述

    JS

    数据类型

    面试官:JavaScript中什么是基本数据类型什么是引用数据类型?以及各个数据类型是如何存储的?⭐⭐⭐⭐⭐

    答:
    基本数据类型有

    • Number
    • String
    • Boolean
    • Null
    • Undefined
    • Symbol(ES6新增数据类型)
    • bigInt

    引用数据类型统称为Object类型,细分的话有

    • Object
    • Array
    • Date
    • Function
    • RegExp

    基本数据类型的数据直接存储在栈中;而引用数据类型的数据存储在堆中,每个对象在堆中有一个引用地址。引用类型在栈中会保存他的引用地址,以便快速查找到堆内存中的对象。

    顺便提一句,栈内存是自动分配内存的。而堆内存是动态分配内存的,不会自动释放。所以每次使用完对象的时候都要把它设置为null,从而减少无用内存的消耗

    类型转换

    面试官:在JS中为什么0.2+0.1>0.3?⭐⭐⭐⭐

    答:

    因为在JS中,浮点数是使用64位固定长度来表示的,其中的1位表示符号位,11位用来表示指数位,剩下的52位尾数位,由于只有52位表示尾数位。

    0.1转为二进制是一个无限循环数0.0001100110011001100......(1100循环)

    小数的十进制转二进制方法:https://jingyan.baidu.com/article/425e69e6e93ca9be15fc1626.html
    要知道,小数的十进制转二进制的方法是和整数不一样的,推荐看一看

    由于只能存储52位尾数位,所以会出现精度缺失,把它存到内存中再取出来转换成十进制就不是原来的0.1了,就变成了0.100000000000000005551115123126,而为什么02+0.1是因为

    <span style="color:#000000"><code class="language-js"><span style="color:#5c6370">// 0.1 和 0.2 都转化成二进制后再进行运算</span>
    <span style="color:#98c379">0.00011001100110011001100110011001100110011001100110011010</span> <span style="color:#669900">+</span>
    <span style="color:#98c379">0.0011001100110011001100110011001100110011001100110011010</span> <span style="color:#669900">=</span>
    <span style="color:#98c379">0.0100110011001100110011001100110011001100110011001100111</span>
    
    <span style="color:#5c6370">// 转成十进制正好是 0.30000000000000004</span>
    </code></span>

    面试官:那为什么0.2+0.3=0.5呢?⭐⭐⭐⭐

    <span style="color:#000000"><code class="language-js"><span style="color:#5c6370">// 0.2 和 0.3 都转化为二进制后再进行计算</span>
    <span style="color:#98c379">0.001100110011001100110011001100110011001100110011001101</span> <span style="color:#669900">+</span>
    <span style="color:#98c379">0.0100110011001100110011001100110011001100110011001101</span> <span style="color:#669900">=</span> 
    <span style="color:#98c379">0.10000000000000000000000000000000000000000000000000001</span> <span style="color:#5c6370">//尾数为大于52位</span>
    
    <span style="color:#5c6370">// 而实际取值只取52位尾数位,就变成了</span>
    <span style="color:#98c379">0.1000000000000000000000000000000000000000000000000000</span>   <span style="color:#5c6370">//0.5</span>
    </code></span>

    答:0.2 和0.3分别转换为二进制进行计算:在内存中,它们的尾数位都是等于52位的,而他们相加必定大于52位,而他们相加又恰巧前52位尾数都是0,截取后恰好是0.1000000000000000000000000000000000000000000000000000也就是0.5

    面试官:那既然0.1不是0.1了,为什么在console.log(0.1)的时候还是0.1呢?⭐⭐⭐

    答:console.log的时候会二进制转换为十进制,十进制再会转为字符串的形式,在转换的过程中发生了取近似值,所以打印出来的是一个近似值的字符串


     

    面试官:判断数据类型有几种方法⭐⭐⭐⭐⭐

    答:

    • typeof

      • 缺点:typeof null的值为Object,无法分辨是null还是Object
    • instanceof

      • 缺点:只能判断对象是否存在于目标对象的原型链上
    • constructor

    • Object.prototype.toString.call()

      • 一种最好的基本类型检测方式 Object.prototype.toString.call() ;它可以区分 null 、 string 、

        boolean 、 number 、 undefined 、 array 、 function 、 object 、 date 、 math 数据类型。

      • 缺点:不能细分为谁谁的实例

    instanceof原理⭐⭐⭐⭐⭐

    • instanceof原理实际上就是查找目标对象的原型链

    面试官:为什么typeof null是Object⭐⭐⭐⭐

    答:

    因为在JavaScript中,不同的对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全是0,自然也就判断为Object

    这个bug是初版本的JavaScript中留下的,扩展一下其他五种标识位:

    • 000 对象
    • 1 整型
    • 010 双精度类型
    • 100字符串
    • 110布尔类型




    面试官:=====有什么区别⭐⭐⭐⭐⭐

    答:

    ===是严格意义上的相等,会比较两边的数据类型和值大小

    • 数据类型不同返回false
    • 数据类型相同,但值大小不同,返回false

    ==是非严格意义上的相等,

    • 两边类型相同,比较大小

    • 两边类型不同,根据下方表格,再进一步进行比较。

      • Null == Undefined ->true
      • String == Number ->先将String转为Number,在比较大小
      • Boolean == Number ->现将Boolean转为Number,在进行比较
      • Object == String,Number,Symbol -> Object 转化为原始类型


     

    面试官:手写call、apply、bind⭐⭐⭐⭐⭐

    答:

    • call和apply实现思路主要是:
      • 判断是否是函数调用,若非函数调用抛异常
      • 通过新对象(context)来调用函数
        • 给context创建一个fn设置为需要调用的函数
        • 结束调用完之后删除fn
    • bind实现思路
      • 判断是否是函数调用,若非函数调用抛异常
      • 返回函数
        • 判断函数的调用方式,是否是被new出来的
          • new出来的话返回空对象,但是实例的__proto__指向_thisprototype
      • 完成函数柯里化
        • Array.prototype.slice.call()

    call:

    apply

     

    bind

     

    面试官:字面量创建对象和new创建对象有什么区别,new内部都实现了什么,手写一个new⭐⭐⭐⭐⭐

    答:

    字面量:

    • 字面量创建对象更简单,方便阅读
    • 不需要作用域解析,速度更快

    new内部:

    • 创建一个新对象
    • 使新对象的__proto__指向原函数的prototype
    • 改变this指向(指向新的obj)并执行该函数,执行结果保存起来作为result
    • 判断执行函数的结果是不是null或Undefined,如果是则返回之前的新对象,如果不是则返回result

    手写new

    <span style="color:#000000"><code class="language-js">    <span style="color:#5c6370">// 手写一个new</span>
        <span style="color:#c678dd">function</span> <span style="color:#61aeee">myNew</span><span style="color:#999999">(</span>fn<span style="color:#999999">,</span> <span style="color:#669900">...</span>args<span style="color:#999999">)</span> <span style="color:#999999">{</span>
          <span style="color:#5c6370">// 创建一个空对象</span>
          <span style="color:#c678dd">let</span> obj <span style="color:#669900">=</span> <span style="color:#999999">{</span><span style="color:#999999">}</span>
          <span style="color:#5c6370">// 使空对象的隐式原型指向原函数的显式原型</span>
          obj<span style="color:#999999">.</span>__proto__ <span style="color:#669900">=</span> fn<span style="color:#999999">.</span>prototype
          <span style="color:#5c6370">// this指向obj</span>
          <span style="color:#c678dd">let</span> result <span style="color:#669900">=</span> fn<span style="color:#999999">.</span><span style="color:#61aeee">apply</span><span style="color:#999999">(</span>obj<span style="color:#999999">,</span> args<span style="color:#999999">)</span>
          <span style="color:#5c6370">// 返回</span>
          <span style="color:#c678dd">return</span> result <span style="color:#c678dd">instanceof</span> Object <span style="color:#669900">?</span> result <span style="color:#999999">:</span> obj
        <span style="color:#999999">}</span>
    </code></span>

    面试官:字面量new出来的对象和 Object.create(null)创建出来的对象有什么区别⭐⭐⭐

    答:

    • 字面量和new创建出来的对象会继承Object的方法和属性,他们的隐式原型会指向Object的显式原型,

    • 而 Object.create(null)创建出来的对象原型为null,作为原型链的顶端,自然也没有继承Object的方法和属性

    执行栈和执行上下文

    面试官:什么是作用域,什么是作用域链?⭐⭐⭐⭐

    答:

    • 规定变量和函数的可使用范围称作作用域
    • 每个函数都有一个作用域链,查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作作用域链。

    面试官:什么是执行栈,什么是执行上下文?⭐⭐⭐⭐

    答:

    执行上下文分为:

    • 全局执行上下文
      • 创建一个全局的window对象,并规定this指向window,执行js的时候就压入栈底,关闭浏览器的时候才弹出
    • 函数执行上下文
      • 每次函数调用时,都会新创建一个函数执行上下文
      • 执行上下文分为创建阶段和执行阶段
        • 创建阶段:函数环境会创建变量对象:arguments对象(并赋值)、函数声明(并赋值)、变量声明(不赋值),函数表达式声明(不赋值);会确定this指向;会确定作用域
        • 执行阶段:变量赋值、函数表达式赋值,使变量对象编程活跃对象
    • eval执行上下文

    执行栈:

    • 首先栈特点:先进后出
    • 当进入一个执行环境,就会创建出它的执行上下文,然后进行压栈,当程序执行完成时,它的执行上下文就会被销毁,进行弹栈。
    • 栈底永远是全局环境的执行上下文,栈顶永远是正在执行函数的执行上下文
    • 只有浏览器关闭的时候全局执行上下文才会弹出

    闭包

    很多人都吃不透js闭包,这里推荐一篇文章:彻底理解js中的闭包

    面试官:什么是闭包?闭包的作用?闭包的应用?⭐⭐⭐⭐⭐

    答:

    函数执行,形成私有的执行上下文,使内部私有变量不受外界干扰,起到保护保存的作用

    作用:

    • 保护
      • 避免命名冲突
    • 保存
      • 解决循环绑定引发的索引问题
    • 变量不会销毁
      • 可以使用函数内部的变量,使变量不会被垃圾回收机制回收

    应用:

    • 设计模式中的单例模式
    • for循环中的保留i的操作
    • 防抖和节流
    • 函数柯里化

    缺点

    • 会出现内存泄漏的问题

    原型和原型链

    面试官:什么是原型?什么是原型链?如何理解⭐⭐⭐⭐⭐

    答:

    原型: 原型分为隐式原型和显式原型,每个对象都有一个隐式原型,它指向自己的构造函数的显式原型。

    原型链: 多个__proto__组成的集合成为原型链

    • 所有实例的__proto__都指向他们构造函数的prototype
    • 所有的prototype都是对象,自然它的__proto__指向的是Object()prototype
    • 所有的构造函数的隐式原型指向的都是Function()的显示原型
    • Object的隐式原型是null

    继承

    面试官:说一说 JS 中的常用的继承方式有哪些?以及各个继承方式的优缺点。⭐⭐⭐⭐⭐

    答:

    原型继承、组合继承、寄生组合继承、ES6的extend

    原型继承

    组合继承

    寄生组合继承

    extend

    内存泄露、垃圾回收机制

    面试官:什么是内存泄漏⭐⭐⭐⭐⭐

    答:

    ​ 内存泄露是指不再用的内存没有被及时释放出来,导致该段内存无法被使用就是内存泄漏

    面试官:为什么会导致的内存泄漏⭐⭐⭐⭐⭐

    答:

    内存泄漏指我们无法在通过js访问某个对象,而垃圾回收机制却认为该对象还在被引用,因此垃圾回收机制不会释放该对象,导致该块内存永远无法释放,积少成多,系统会越来越卡以至于崩溃

    面试官:垃圾回收机制都有哪些策略?⭐⭐⭐⭐⭐

    答:

    • 标记清除法
      • 垃圾回收机制获取根并标记他们,然后访问并标记所有来自它们的引用,然后在访问这些对象并标记它们的引用…如此递进结束后若发现有没有标记的(不可达的)进行删除,进入执行环境的不能进行删除
    • 引用计数法
      • 当声明一个变量并给该变量赋值一个引用类型的值时候,该值的计数+1,当该值赋值给另一个变量的时候,该计数+1,当该值被其他值取代的时候,该计数-1,当计数变为0的时候,说明无法访问该值了,垃圾回收机制清除该对象

    深拷贝和浅拷贝

    手写浅拷贝深拷贝⭐⭐⭐⭐⭐

    深拷贝能使用hash递归的方式写出来就可以了
    不过技多不压身,推荐还是看一看使用while实现深拷贝方法

     

    单线程,同步异步

    面试官:为什么JS是单线程的?⭐⭐⭐⭐⭐

    **答:**因为JS里面有可视的Dom,如果是多线程的话,这个线程正在删除DOM节点,另一个线程正在编辑Dom节点,导致浏览器不知道该听谁的

    面试官:如何实现异步编程?

    **答:**回调函数

    面试官:Generator是怎么样使用的以及各个阶段的变化如何?⭐⭐⭐

    答:

    • 首先生成器是一个函数,用来返回迭代器的

    • 调用生成器后不会立即执行,而是通过返回的迭代器来控制这个生成器的一步一步执行的

    • 通过调用迭代器的next方法来请求一个一个的值,返回的对象有两个属性,一个是value,也就是值;另一个是done,是个布尔类型,done为true说明生成器函数执行完毕,没有可返回的值了,

    • donetrue后继续调用迭代器的next方法,返回值的valueundefined

    状态变化:

    • 每当执行到yield属性的时候,都会返回一个对象
    • 这时候生成器处于一个非阻塞的挂起状态
    • 调用迭代器的next方法的时候,生成器又从挂起状态改为执行状态,继续上一次的执行位置执行
    • 直到遇到下一次yield依次循环
    • 直到代码没有yield了,就会返回一个结果对象donetruevalueundefined

    面试官:说说 Promise 的原理?你是如何理解 Promise 的?⭐⭐⭐⭐⭐

    • 做到会写简易版的promise和all函数就可以

    答:

    <span style="color:#000000"><code class="language-js"><span style="color:#c678dd">class</span> MyPromise2 <span style="color:#999999">{</span>
          <span style="color:#61aeee">constructor</span><span style="color:#999999">(</span>executor<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#5c6370">// 规定状态</span>
            <span style="color:#c678dd">this</span><span style="color:#999999">.</span>state <span style="color:#669900">=</span> <span style="color:#669900">"pending"</span>
            <span style="color:#5c6370">// 保存 `resolve(res)` 的res值</span>
            <span style="color:#c678dd">this</span><span style="color:#999999">.</span>value <span style="color:#669900">=</span> undefined
            <span style="color:#5c6370">// 保存 `reject(err)` 的err值</span>
            <span style="color:#c678dd">this</span><span style="color:#999999">.</span>reason <span style="color:#669900">=</span> undefined
            <span style="color:#5c6370">// 成功存放的数组</span>
            <span style="color:#c678dd">this</span><span style="color:#999999">.</span>successCB <span style="color:#669900">=</span> <span style="color:#999999">[</span><span style="color:#999999">]</span>
            <span style="color:#5c6370">// 失败存放的数组</span>
            <span style="color:#c678dd">this</span><span style="color:#999999">.</span>failCB <span style="color:#669900">=</span> <span style="color:#999999">[</span><span style="color:#999999">]</span>
    
    
            <span style="color:#c678dd">let</span> <span style="color:#61aeee">resolve</span> <span style="color:#669900">=</span> <span style="color:#999999">(</span>value<span style="color:#999999">)</span> <span style="color:#669900">=></span> <span style="color:#999999">{</span>
              <span style="color:#c678dd">if</span> <span style="color:#999999">(</span><span style="color:#c678dd">this</span><span style="color:#999999">.</span>state <span style="color:#669900">===</span> <span style="color:#669900">"pending"</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>state <span style="color:#669900">=</span> <span style="color:#669900">"fulfilled"</span>
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>value <span style="color:#669900">=</span> value
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>successCB<span style="color:#999999">.</span><span style="color:#61aeee">forEach</span><span style="color:#999999">(</span>f <span style="color:#669900">=></span> <span style="color:#61aeee">f</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span>
              <span style="color:#999999">}</span>
            <span style="color:#999999">}</span>
            <span style="color:#c678dd">let</span> <span style="color:#61aeee">reject</span> <span style="color:#669900">=</span> <span style="color:#999999">(</span>reason<span style="color:#999999">)</span> <span style="color:#669900">=></span> <span style="color:#999999">{</span>
              <span style="color:#c678dd">if</span> <span style="color:#999999">(</span><span style="color:#c678dd">this</span><span style="color:#999999">.</span>state <span style="color:#669900">===</span> <span style="color:#669900">"pending"</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>state <span style="color:#669900">=</span> <span style="color:#669900">"rejected"</span>
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>value <span style="color:#669900">=</span> value
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>failCB<span style="color:#999999">.</span><span style="color:#61aeee">forEach</span><span style="color:#999999">(</span>f <span style="color:#669900">=></span> <span style="color:#61aeee">f</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span>
              <span style="color:#999999">}</span>
            <span style="color:#999999">}</span>
    
            <span style="color:#c678dd">try</span> <span style="color:#999999">{</span>
              <span style="color:#5c6370">// 执行</span>
              <span style="color:#61aeee">executor</span><span style="color:#999999">(</span>resolve<span style="color:#999999">,</span> reject<span style="color:#999999">)</span>
            <span style="color:#999999">}</span> <span style="color:#c678dd">catch</span> <span style="color:#999999">(</span>error<span style="color:#999999">)</span> <span style="color:#999999">{</span>
              <span style="color:#5c6370">// 若出错,直接调用reject</span>
              <span style="color:#61aeee">reject</span><span style="color:#999999">(</span>error<span style="color:#999999">)</span>
            <span style="color:#999999">}</span>
          <span style="color:#999999">}</span>
          <span style="color:#61aeee">then</span><span style="color:#999999">(</span>onFulfilled<span style="color:#999999">,</span> onRejected<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#c678dd">if</span> <span style="color:#999999">(</span><span style="color:#c678dd">this</span><span style="color:#999999">.</span>state <span style="color:#669900">===</span> <span style="color:#669900">"fulfilled"</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
              <span style="color:#61aeee">onFulfilled</span><span style="color:#999999">(</span><span style="color:#c678dd">this</span><span style="color:#999999">.</span>value<span style="color:#999999">)</span>
            <span style="color:#999999">}</span>
            <span style="color:#c678dd">if</span> <span style="color:#999999">(</span><span style="color:#c678dd">this</span><span style="color:#999999">.</span>state <span style="color:#669900">===</span> <span style="color:#669900">"rejected"</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
              <span style="color:#61aeee">onRejected</span><span style="color:#999999">(</span><span style="color:#c678dd">this</span><span style="color:#999999">.</span>value<span style="color:#999999">)</span>
            <span style="color:#999999">}</span>
            <span style="color:#c678dd">if</span> <span style="color:#999999">(</span><span style="color:#c678dd">this</span><span style="color:#999999">.</span>state <span style="color:#669900">===</span> <span style="color:#669900">"pending"</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
              <span style="color:#c678dd">this</span><span style="color:#999999">.</span>successCB<span style="color:#999999">.</span><span style="color:#61aeee">push</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#669900">=></span> <span style="color:#999999">{</span> <span style="color:#61aeee">onFulfilled</span><span style="color:#999999">(</span><span style="color:#c678dd">this</span><span style="color:#999999">.</span>value<span style="color:#999999">)</span> <span style="color:#999999">}</span><span style="color:#999999">)</span>
              <span style="color:#c678dd">this</span><span style="color:#999999">.</span>failCB<span style="color:#999999">.</span><span style="color:#61aeee">push</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#669900">=></span> <span style="color:#999999">{</span> <span style="color:#61aeee">onRejected</span><span style="color:#999999">(</span><span style="color:#c678dd">this</span><span style="color:#999999">.</span>reason<span style="color:#999999">)</span> <span style="color:#999999">}</span><span style="color:#999999">)</span>
            <span style="color:#999999">}</span>
          <span style="color:#999999">}</span>
        <span style="color:#999999">}</span>
    
    
        Promise<span style="color:#999999">.</span><span style="color:#61aeee">all</span> <span style="color:#669900">=</span> <span style="color:#c678dd">function</span> <span style="color:#999999">(</span>promises<span style="color:#999999">)</span> <span style="color:#999999">{</span>
          <span style="color:#c678dd">let</span> list <span style="color:#669900">=</span> <span style="color:#999999">[</span><span style="color:#999999">]</span>
          <span style="color:#c678dd">let</span> count <span style="color:#669900">=</span> <span style="color:#98c379">0</span>
          <span style="color:#c678dd">function</span> <span style="color:#61aeee">handle</span><span style="color:#999999">(</span>i<span style="color:#999999">,</span> data<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            list<span style="color:#999999">[</span>i<span style="color:#999999">]</span> <span style="color:#669900">=</span> data
            count<span style="color:#669900">++</span>
            <span style="color:#c678dd">if</span> <span style="color:#999999">(</span>count <span style="color:#669900">==</span> promises<span style="color:#999999">.</span>length<span style="color:#999999">)</span> <span style="color:#999999">{</span>
              <span style="color:#61aeee">resolve</span><span style="color:#999999">(</span>list<span style="color:#999999">)</span>
            <span style="color:#999999">}</span>
          <span style="color:#999999">}</span>
          <span style="color:#c678dd">return</span> <span style="color:#61aeee">Promise</span><span style="color:#999999">(</span><span style="color:#999999">(</span>resolve<span style="color:#999999">,</span> reject<span style="color:#999999">)</span> <span style="color:#669900">=></span> <span style="color:#999999">{</span>
            <span style="color:#c678dd">for</span> <span style="color:#999999">(</span><span style="color:#c678dd">let</span> i <span style="color:#669900">=</span> <span style="color:#98c379">0</span><span style="color:#999999">;</span> i <span style="color:#669900"><</span> promises<span style="color:#999999">.</span>length<span style="color:#999999">;</span> i<span style="color:#669900">++</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
              promises<span style="color:#999999">[</span>i<span style="color:#999999">]</span><span style="color:#999999">.</span><span style="color:#61aeee">then</span><span style="color:#999999">(</span>res <span style="color:#669900">=></span> <span style="color:#999999">{</span>
                <span style="color:#61aeee">handle</span><span style="color:#999999">(</span>i<span style="color:#999999">,</span> res<span style="color:#999999">)</span>
              <span style="color:#999999">}</span><span style="color:#999999">,</span> err <span style="color:#669900">=></span> <span style="color:#61aeee">reject</span><span style="color:#999999">(</span>err<span style="color:#999999">)</span><span style="color:#999999">)</span>
            <span style="color:#999999">}</span>
          <span style="color:#999999">}</span><span style="color:#999999">)</span>
        <span style="color:#999999">}</span>
    </code></span>

    面试官:以下代码的执行顺序是什么⭐⭐⭐⭐⭐

    答:

    <span style="color:#000000"><code class="language-js">  <span style="color:#c678dd">async</span> <span style="color:#c678dd">function</span> <span style="color:#61aeee">async1</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
       console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span><span style="color:#669900">'async1 start'</span><span style="color:#999999">)</span>
       <span style="color:#c678dd">await</span> <span style="color:#61aeee">async2</span><span style="color:#999999">(</span><span style="color:#999999">)</span>
       console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span><span style="color:#669900">'async1 end'</span><span style="color:#999999">)</span>
      <span style="color:#999999">}</span>
      <span style="color:#c678dd">async</span> <span style="color:#c678dd">function</span> <span style="color:#61aeee">async2</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
       console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span><span style="color:#669900">'async2'</span><span style="color:#999999">)</span>
      <span style="color:#999999">}</span>
      <span style="color:#61aeee">async1</span><span style="color:#999999">(</span><span style="color:#999999">)</span>
      console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span><span style="color:#669900">'script start'</span><span style="color:#999999">)</span>
    
    <span style="color:#5c6370">//执行到await时,如果返回的不是一个promise对象,await会阻塞下面代码(当前async代码块的代码),会先执行async外的同步代码(在这之前先看看await中函数的同步代码,先把同步代码执行完),等待同步代码执行完之后,再回到async内部继续执行</span>
    <span style="color:#5c6370">//执行到await时,如果返回的是一个promise对象,await会阻塞下面代码(当前async代码块的代码),会先执行async外的同步代码(在这之前先看看await中函数的同步代码,先把同步代码执行完),等待同步代码执行完之后,再回到async内部等promise状态达到fulfill的时候再继续执行下面的代码</span>
    <span style="color:#5c6370">//所以结果为</span>
    <span style="color:#5c6370">//async1 start</span>
    <span style="color:#5c6370">//async2</span>
    <span style="color:#5c6370">//script start</span>
    <span style="color:#5c6370">//async1 end</span>
    </code></span>

    面试官:宏任务和微任务都有哪些⭐⭐⭐⭐⭐

    答:

    • 宏任务:scriptsetTimeOutsetIntervalsetImmediate
    • 微任务:promise.then,process.nextTickObject.observeMutationObserver
    • 注意:Promise是同步任务

    面试官:宏任务和微任务都是怎样执行的⭐⭐⭐⭐⭐

    答:

    • 执行宏任务script,
    • 进入script后,所有的同步任务主线程执行
    • 所有宏任务放入宏任务执行队列
    • 所有微任务放入微任务执行队列
    • 先清空微任务队列,
    • 再取一个宏任务,执行,再清空微任务队列
    • 依次循环

    例题1

    解析

    1. 首先浏览器执行Js代码由上至下顺序,遇到setTimeout,把setTimeout分发到宏任务Event Queue中
    2. new Promise属于主线程任务直接执行打印2
    3. Promis下的then方法属于微任务,把then分到微任务 Event Queue中
    4. console.log(‘4’)属于主线程任务,直接执行打印4
    5. 又遇到new Promise也是直接执行打印5,Promise 下到then分发到微任务Event Queue中
    6. 又遇到setTimouse也是直接分发到宏任务Event Queue中,等待执行
    7. console.log(‘10’)属于主线程任务直接执行
    8. 遇到bar()函数调用,执行构造函数内到代码,打印8,在bar函数中调用foo函数,执行foo函数到中代码,打印9
    9. 主线程中任务执行完后,就要执行分发到微任务Event Queue中代码,实行先进先出,所以依次打印3,6
    10. 微任务Event Queue中代码执行完,就执行宏任务Event Queue中代码,也是先进先出,依次打印1,7。
    • 最终结果:2,4,5,10,8,9,3,6,1,7

    例题2

    运行结果: 5 7 10 8 1 2 4 6 3

    变量提升

    面试官:变量和函数怎么进行提升的?优先级是怎么样的?⭐⭐⭐⭐

    答:

    • 对所有函数声明进行提升(除了函数表达式和箭头函数),引用类型的赋值
      • 开辟堆空间
      • 存储内容
      • 将地址赋给变量
    • 对变量进行提升,只声明,不赋值,值为undefined

    面试官:var let const 有什么区别⭐⭐⭐⭐⭐

    答:

    • var
      • var声明的变量可进行变量提升,let和const不会
      • var可以重复声明
      • var在非函数作用域中定义是挂在到window上的
    • let
      • let声明的变量只在局部起作用
      • let防止变量污染
      • 不可在声明
    • const
      • 具有let的所有特征
      • 不可被改变
        • 如果使用const声明的是对象的话,是可以修改对象里面的值的

    面试官:箭头函数和普通函数的区别?箭头函数可以当做构造函数 new 吗?⭐⭐⭐⭐⭐

    • 箭头函数是普通函数的简写,但是它不具备很多普通函数的特性
    • 第一点,this指向问题,箭头函数的this指向它定义时所在的对象,而不是调用时所在的对象
    • 不会进行函数提升
    • 没有arguments对象,不能使用arguments,如果要获取参数的话可以使用rest运算符
    • 没有yield属性,不能作为生成器Generator使用
    • 不能new
      • 没有自己的this,不能调用call和apply
      • 没有prototype,new关键字内部需要把新对象的_proto_指向函数的prototype

    面试官:说说你对代理的理解⭐⭐⭐

    • 代理有几种定义方式
      • 字面量定义,对象里面的 get和set
      • 类定义, class 中的getset
      • Proxy对象,里面传两个对象,第一个对象是目标对象target,第二个对象是专门放get和set的handler对象。Proxy和上面两个的区别在于Proxy专门对对象的属性进行get和set
    • 代理的实际应用有
      • Vue的双向绑定 vue2用的是Object.defineProperty,vue3用的是proxy
      • 校验值
      • 计算属性值(get的时候加以修饰)

    面试官:为什么要使用模块化?都有哪几种方式可以实现模块化,各有什么特点?⭐⭐⭐

    • 为什么要使用模块化
      • 防止命名冲突
      • 更好的分离,按需加载
      • 更好的复用性
      • 更高的维护性

    面试官:exportsmodule.exports有什么区别?⭐⭐⭐

    • 导出方式不一样
      • exports.xxx='xxx'
      • module.export = {}
    • exportsmodule.exports的引用,两个指向的是用一个地址,而require能看到的只有module.exports

    面试官:JS模块包装格式有哪些?⭐⭐⭐

    • commonjs

      • 同步运行,不适合前端
    • AMD

      • 异步运行
      • 异步模块定义,主要采用异步的方式加载模块,模块的加载不影响后面代码的执行。所有依赖这个模块的语句都写在一个回调函数中,模块加载完毕,再执行回调函数
    • CMD

      • 异步运行
      • seajs 规范

    面试官:ES6和commonjs的区别⭐⭐⭐

    • commonjs模块输出的是值的拷贝,而ES6输出的值是值的引用
    • commonjs是在运行时加载,是一个对象,ES6是在编译时加载,是一个代码块
    • commonjs的this指向当前模块,ES6的this指向undefined

    哎呀呀呀,不简单,你竟然都看到这里了,看看进度条,已经达到一半了
    不过——在这之前,先问问自己,前面的都掌握了吗??
    如果你还没有,赶紧滚回去看!
    如果你掌握前面的了,那么准备迎接下一个boss——计算机网络

    在这里插入图片描述

    跨域

    面试官:跨域的方式都有哪些?他们的特点是什么 ⭐⭐⭐⭐⭐

    • JSONP⭐⭐⭐⭐⭐

      • JSONP通过同源策略涉及不到的"漏洞",也就是像img中的srclink标签的href,scriptsrc都没有被同源策略限制到

      • JSONP只能get请求

      • 源码:

        <span style="color:#000000"><code class="language-js">    <span style="color:#c678dd">function</span> <span style="color:#61aeee">addScriptTag</span><span style="color:#999999">(</span>src<span style="color:#999999">)</span> <span style="color:#999999">{</span>
              <span style="color:#c678dd">var</span> script <span style="color:#669900">=</span> document<span style="color:#999999">.</span><span style="color:#61aeee">createElement</span><span style="color:#999999">(</span><span style="color:#669900">"script"</span><span style="color:#999999">)</span>
              script<span style="color:#999999">.</span><span style="color:#61aeee">setAttribute</span><span style="color:#999999">(</span><span style="color:#669900">'type'</span><span style="color:#999999">,</span><span style="color:#669900">'text/javascript'</span><span style="color:#999999">)</span>
              script<span style="color:#999999">.</span>src <span style="color:#669900">=</span> src
              document<span style="color:#999999">.</span><span style="color:#61aeee">appendChild</span><span style="color:#999999">(</span>script<span style="color:#999999">)</span>
            <span style="color:#999999">}</span>
        
            
            <span style="color:#5c6370">// 回调函数</span>
            <span style="color:#c678dd">function</span> <span style="color:#61aeee">endFn</span><span style="color:#999999">(</span>res<span style="color:#999999">)</span> <span style="color:#999999">{</span>
              console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span>res<span style="color:#999999">.</span>message<span style="color:#999999">)</span><span style="color:#999999">;</span>
            <span style="color:#999999">}</span>
        
            <span style="color:#5c6370">// 前后端商量好,后端如果传数据的话,返回`endFn({message:'hello'})`</span>
        </code></span>
    • document.domain⭐

      • 只能跨一级域名相同的域(www.qq.om和www.id.qq.com , 二者都有qq.com)

      • 使用方法

        • >表示输入, <表示输出 ,以下是在www.id.qq.com网站下执行的操作

        • <span style="color:#000000"><code class="language-js"><span style="color:#669900">></span> <span style="color:#c678dd">var</span> w <span style="color:#669900">=</span> window<span style="color:#999999">.</span><span style="color:#61aeee">open</span><span style="color:#999999">(</span><span style="color:#669900">"https://www.qq.com"</span><span style="color:#999999">)</span>
          <span style="color:#669900"><</span> undefined
          <span style="color:#669900">></span> w<span style="color:#999999">.</span>document
          ✖ <span style="color:#98c379">VM3061</span><span style="color:#999999">:</span><span style="color:#98c379">1</span> Uncaught DOMException<span style="color:#999999">:</span> Blocked a frame <span style="color:#c678dd">with</span> origin <span style="color:#669900">"https://id.qq.com"</span> <span style="color:#c678dd">from</span> accessing a cross<span style="color:#669900">-</span>origin frame<span style="color:#999999">.</span>
              at <span style="color:#669900"><</span>anonymous<span style="color:#669900">></span><span style="color:#999999">:</span><span style="color:#98c379">1</span><span style="color:#999999">:</span><span style="color:#98c379">3</span>
          <span style="color:#669900">></span> document<span style="color:#999999">.</span>domain
          <span style="color:#669900"><</span> <span style="color:#669900">"id.qq.com"</span>
          <span style="color:#669900">></span> document<span style="color:#999999">.</span>domain <span style="color:#669900">=</span> <span style="color:#669900">'qq.com'</span>
          <span style="color:#669900"><</span> <span style="color:#669900">"qq.com"</span>
          <span style="color:#669900">></span> w<span style="color:#999999">.</span>document
          <span style="color:#669900"><</span> #document
          </code></span>
    • location.hash+iframe⭐⭐

      • 因为hash传值只能单向传输,所有可以通过一个中间网页,a若想与b进行通信,可以通过一个与a同源的c作为中间网页,a传给b,b传给c,c再传回a

        • 具体做法:在a中放一个回调函数,方便c回调。放一个iframe标签,随后传值

        • <span style="color:#000000"><code class="language-html"><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"><</span>iframe</span> <span style="color:#d19a66">id</span><span style="color:#669900"><span style="color:#999999">=</span><span style="color:#999999">"</span>iframe<span style="color:#999999">"</span></span> <span style="color:#d19a66">src</span><span style="color:#669900"><span style="color:#999999">=</span><span style="color:#999999">"</span>http://www.domain2.com/b.html<span style="color:#999999">"</span></span><span style="color:#d19a66"> <span style="color:#d19a66">style</span></span><span style="color:#999999">="</span><span style="color:#669900"><span style="color:#98c379">display</span><span style="color:#999999">:</span>none<span style="color:#999999">;</span></span><span style="color:#999999">"</span><span style="color:#999999">></span></span><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"></</span>iframe</span><span style="color:#999999">></span></span>
          <span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"><</span>script</span><span style="color:#999999">></span></span>
              <span style="color:#c678dd">var</span> iframe <span style="color:#669900">=</span> document<span style="color:#999999">.</span><span style="color:#61aeee">getElementById</span><span style="color:#999999">(</span><span style="color:#669900">'iframe'</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
          
              <span style="color:#5c6370">// 向b.html传hash值</span>
              <span style="color:#61aeee">setTimeout</span><span style="color:#999999">(</span><span style="color:#c678dd">function</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
                  iframe<span style="color:#999999">.</span>src <span style="color:#669900">=</span> iframe<span style="color:#999999">.</span>src <span style="color:#669900">+</span> <span style="color:#669900">'#user=admin'</span><span style="color:#999999">;</span>
              <span style="color:#999999">}</span><span style="color:#999999">,</span> <span style="color:#98c379">1000</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
              
              <span style="color:#5c6370">// 开放给同域c.html的回调方法</span>
              <span style="color:#c678dd">function</span> <span style="color:#61aeee">onCallback</span><span style="color:#999999">(</span>res<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                  <span style="color:#61aeee">alert</span><span style="color:#999999">(</span><span style="color:#669900">'data from c.html ---> '</span> <span style="color:#669900">+</span> res<span style="color:#999999">)</span><span style="color:#999999">;</span>
              <span style="color:#999999">}</span>
          <span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"></</span>script</span><span style="color:#999999">></span></span>
          </code></span>
        • 在b中监听哈希值改变,一旦改变,把a要接收的值传给c

        • <span style="color:#000000"><code class="language-html"><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"><</span>iframe</span> <span style="color:#d19a66">id</span><span style="color:#669900"><span style="color:#999999">=</span><span style="color:#999999">"</span>iframe<span style="color:#999999">"</span></span> <span style="color:#d19a66">src</span><span style="color:#669900"><span style="color:#999999">=</span><span style="color:#999999">"</span>http://www.domain1.com/c.html<span style="color:#999999">"</span></span><span style="color:#d19a66"> <span style="color:#d19a66">style</span></span><span style="color:#999999">="</span><span style="color:#669900"><span style="color:#98c379">display</span><span style="color:#999999">:</span>none<span style="color:#999999">;</span></span><span style="color:#999999">"</span><span style="color:#999999">></span></span><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"></</span>iframe</span><span style="color:#999999">></span></span>
          <span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"><</span>script</span><span style="color:#999999">></span></span>
              <span style="color:#c678dd">var</span> iframe <span style="color:#669900">=</span> document<span style="color:#999999">.</span><span style="color:#61aeee">getElementById</span><span style="color:#999999">(</span><span style="color:#669900">'iframe'</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
          
              <span style="color:#5c6370">// 监听a.html传来的hash值,再传给c.html</span>
              window<span style="color:#999999">.</span><span style="color:#61aeee">onhashchange</span> <span style="color:#669900">=</span> <span style="color:#c678dd">function</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
                  iframe<span style="color:#999999">.</span>src <span style="color:#669900">=</span> iframe<span style="color:#999999">.</span>src <span style="color:#669900">+</span> location<span style="color:#999999">.</span>hash<span style="color:#999999">;</span>
              <span style="color:#999999">}</span><span style="color:#999999">;</span>
          <span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"></</span>script</span><span style="color:#999999">></span></span>
          </code></span>
        • 在c中监听哈希值改变,一旦改变,调用a中的回调函数

        • <span style="color:#000000"><code class="language-html"><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"><</span>script</span><span style="color:#999999">></span></span>
              <span style="color:#5c6370">// 监听b.html传来的hash值</span>
              window<span style="color:#999999">.</span><span style="color:#61aeee">onhashchange</span> <span style="color:#669900">=</span> <span style="color:#c678dd">function</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
                  <span style="color:#5c6370">// 再通过操作同域a.html的js回调,将结果传回</span>
                  window<span style="color:#999999">.</span>parent<span style="color:#999999">.</span>parent<span style="color:#999999">.</span><span style="color:#61aeee">onCallback</span><span style="color:#999999">(</span><span style="color:#669900">'hello: '</span> <span style="color:#669900">+</span> location<span style="color:#999999">.</span>hash<span style="color:#999999">.</span><span style="color:#61aeee">replace</span><span style="color:#999999">(</span><span style="color:#669900">'#user='</span><span style="color:#999999">,</span> <span style="color:#669900">''</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
              <span style="color:#999999">}</span><span style="color:#999999">;</span>
          <span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"></</span>script</span><span style="color:#999999">></span></span>
          </code></span>
    • window.name+iframe⭐⭐

      • 利Access用window.name不会改变(而且很大)来获取数据,
      • a要获取b的数据,b中把数据转为json格式放到window.name
    • postMessage

      • a窗口向b窗口发送数据,先把data转为json格式,在发送。提前设置好messge监听
      • b窗口进行message监听,监听到了以同样的方式返回数据,
      • a窗口监听到message,在进行一系列操作
    • CORS⭐⭐⭐⭐⭐

      • 通过自定义请求头来让服务器和浏览器进行沟通
      • 有简单请求和非简单请求
      • 满足以下条件,就是简单请求
        • 请求方法是HEAD、POST、GET
        • 请求头只有AcceptAcceptLanguageContentTypeContentLanguageLast-Event-Id
      • 简单请求,浏览器自动添加一个Origin字段
        • 同时后端需要设置的请求头
          • Access-Control-Allow-Origin --必须
          • Access-Control-Expose-Headers
            • XMLHttpRequest只能拿到六个字段,要想拿到其他的需要在这里指定
        • Access-Control-Allow-Credentials --是否可传cookie
        • 要是想传cookie,前端需要设置xhr.withCredentials = true,后端设置Access-Control-Allow-Credentials
      • 非简单请求,浏览器判断是否为简单请求,如果是非简单请求,则 浏览器先发送一个header头为option的请求进行预检
        • 预检请求格式(请求行 的请求方法为OPTIONS(专门用来询问的))
          • Origin
          • Access-Control-Request-Method
          • Access-Control-Request-Header
        • 浏览器检查了Origin、Access-Control-Allow-Method和Access-Control-Request-Header之后确认允许就可以做出回应了
        • 通过预检后,浏览器接下来的每次请求就类似于简单请求了
    • nginx代理跨域⭐⭐⭐⭐

      • nginx模拟一个虚拟服务器,因为服务器与服务器之间是不存在跨域的,
      • 发送数据时 ,客户端->nginx->服务端
      • 返回数据时,服务端->nginx->客户端

    网络原理

    面试官:讲一讲三次握手四次挥手,为什么是三次握手四而不是两次握手?⭐⭐⭐⭐⭐

    • 客户端和服务端之间通过三次握手建立连接,四次挥手释放连接

    • 三次握手,客户端先向服务端发起一个SYN包,进入SYN_SENT状态,服务端收到SYN后,给客户端返回一个ACK+SYN包,表示已收到SYN,并进入SYN_RECEIVE状态,最后客户端再向服务端发送一个ACK包表示确认,双方进入establish状态。

      • 之所以是三次握手而不是两次,是因为如果只有两次,在服务端收到SYN后,向客户端返回一个ACK确认就进入establish状态,万一这个请求中间遇到网络情况而没有传给客户端,客户端一直是等待状态,后面服务端发送的信息客户端也接受不到了。
    • 四次挥手,首先客户端向服务端发送一个FIN包,进入FIN_WAIT1状态,服务端收到后,向客户端发送ACK确认包,进入CLOSE_WAIT状态,然后客户端收到ACK包后进入FIN_WAIT2状态,然后服务端再把自己剩余没传完的数据发送给客户端,发送完毕后在发送一个FIN+ACK包,进入LAST_ACK(最后确认)状态,客户端收到FIN+ACK包后,再向服务端发送ACK包,在等待两个周期后在关闭连接

      • 之所以等待两个周期是因为最后服务端发送的ACK包可能会丢失,如果不等待2个周期的话,服务端在没收收到ACK包之前,会不停的重复发送FIN包而不关闭,所以得等待两个周期

    面试官:HTTP的结构⭐⭐⭐⭐

    • 请求行 请求头 空行 请求体
      • 请求行包括 http版本号,url,请求方式
      • 响应行包括版本号,状态码,原因

    HTTP头都有哪些字段⭐⭐⭐⭐

    • 请求头
      • cache-control 是否使用缓存
      • Connection:keep-alive 与服务器的连接状态
      • Host 主机域
    • 返回头
      • cache-control
      • etag 唯一标识,缓存用的
      • last-modified最后修改时间

    面试官:说说你知道的状态码⭐⭐⭐⭐⭐

    • 2开头的表示成功
      • 一般见到的就是200
    • 3开头的表示重定向
      • 301永久重定向
      • 302临时重定向
      • 304表示可以在缓存中取数据(协商缓存)
    • 4开头表示客户端错误
      • 403跨域
      • 404请求资源不存在
    • 5开头表示服务端错误
      • 500

    网络OSI七层模型都有哪些?TCP是哪一层的⭐⭐⭐⭐

    • 七层模型
      • 应用层
      • 表示层
      • 会话层
      • 传输层
      • 网络层
      • 数据链路层
      • 物理层
    • TCP属于传输层

    面试官:http1.0和http1.1,还有http2有什么区别?⭐⭐⭐⭐

    • http0.9只能进行get请求
    • http1.0添加了POST,HEAD,OPTION,PUT,DELETE等
    • http1.1增加了长连接keep-alive,增加了host域,而且节约带宽
    • http2 多路复用,头部压缩,服务器推送

    面试官:https和http有什么区别,https的实现原理?⭐⭐⭐⭐⭐

    • http无状态无连接,而且是明文传输,不安全
    • https传输内容加密,身份验证,保证数据完整性
    • https实现原理⭐⭐⭐⭐⭐
      • 首先客户端向服务端发起一个随机值,以及一个加密算法
      • 服务端收到后返回一个协商好的加密算法,以及另一个随机值
      • 服务端在发送一个公钥CA
      • 客户端收到以后先验证CA是否有效,如果无效则报错弹窗,有过有效则进行下一步操作
      • 客户端使用之前的两个随机值和一个预主密钥组成一个会话密钥,在通过服务端传来的公钥加密把会话密钥发送给服务端
      • 服务端收到后使用私钥解密,得到两个随机值和预主密钥,然后组装成会话密钥
      • 客户端在向服务端发起一条信息,这条信息使用会话秘钥加密,用来验证服务端时候能收到加密的信息
      • 服务端收到信息后返回一个会话秘钥加密的信息
      • 都收到以后SSL层连接建立成功

    面试官:localStorage、SessionStorage、cookie、session 之间有什么区别⭐⭐⭐⭐⭐

    • localStorage
      • 生命周期:关闭浏览器后数据依然保留,除非手动清除,否则一直在
      • 作用域:相同浏览器的不同标签在同源情况下可以共享localStorage
    • sessionStorage
      • 生命周期:关闭浏览器或者标签后即失效
      • 作用域:只在当前标签可用,当前标签的iframe中且同源可以共享
    • cookie
      • 是保存在客户端的,一般由后端设置值,可以设置过期时间
      • 储存大小只有4K
      • 一般用来保存用户的信息的
      • 在http下cookie是明文传输的,较不安全
      • cookie属性有
        • http-only:不能被客户端更改访问,防止XSS攻击(保证cookie安全性的操作)
        • Secure:只允许在https下传输
        • Max-age: cookie生成后失效的秒数
        • expire: cookie的最长有效时间,若不设置则cookie生命期与会话期相同
    • session
      • session是保存在服务端的
      • session的运行依赖sessionId,而sessionId又保存在cookie中,所以如果禁用的cookie,session也是不能用的,不过硬要用也可以,可以把sessionId保存在URL中
      • session一般用来跟踪用户的状态
      • session 的安全性更高,保存在服务端,不过一般为使服务端性能更加,会考虑部分信息保存在cookie中

    localstorage存满了怎么办?⭐⭐⭐

    • 划分域名,各域名下的存储空间由各业务组统一规划使用
    • 跨页面传数据:考虑单页应用、采用url传输数据
    • 最后兜底方案:情调别人的存储

    怎么使用cookie保存用户信息⭐⭐⭐

    • document.cookie(“名字 = 数据;expire=时间”)

    怎么删除cookie⭐⭐⭐

    • 目前没有提供删除的操作,但是可以把它的Max-age设置为0,也就是立马失效,也就是删除了

    面试官:Get和Post的区别⭐⭐⭐⭐⭐

    https://www.zhihu.com/question/28586791

    • 冪等/不冪等(可缓存/不可缓存)
      • get请求是冪等的,所以get请求的数据是可以缓存的
      • 而post请求是不冪等的,查询查询对数据是有副作用的,是不可缓存的
    • 传参
      • get传参,参数是在url中的
        • 准确的说get传参也可以放到body中,只不过不推荐使用
      • post传参,参数是在请求体中
        • 准确的说post传参也可以放到url中,只不过不推荐使用
    • 安全性
      • get较不安全
      • post较为安全
      • 准确的说两者都不安全,都是明文传输的,在路过公网的时候都会被访问到,不管是url还是header还是body,都会被访问到,要想做到安全,就需要使用https
    • 参数长度
      • get参数长度有限,是较小的
        • 准确来说,get在url传参的时候是很小的
      • post传参长度不受限制
    • 发送数据
      • post传参发送两个请求包,一个是请求头,一个是请求体,请求头发送后服务器进行验证,要是验证通过的话就会给客户端发送一个100-continue的状态码,然后就会发送请求体
    • 字符编码
      • get在url上传输的时候只允许ASCII编码

    面试官:讲讲http缓存⭐⭐⭐⭐⭐

    https://www.jianshu.com/p/9c95db596df5

    • 缓存分为强缓存和协商缓存
    • 强缓存
      • 在浏览器加载资源时,先看看cache-control里的max-age,判断数据有没有过期,如果没有直接使用该缓存 ,有些用户可能会在没有过期的时候就点了刷新按钮,这个时候浏览器就回去请求服务端,要想避免这样做,可以在cache-control里面加一个immutable.
      • public
        • 允许客户端和虚拟服务器缓存该资源,cache-control中的一个属性
      • private
        • 只允许客户端缓存该资源
      • no-storage
        • 不允许强缓存,可以协商缓存
      • no-cache
        • 不允许缓存
    • 协商缓存
      • 浏览器加载资源时,没有命中强缓存,这时候就去请求服务器,去请求服务器的时候,会带着两个参数,一个是If-None-Match,也就是响应头中的etag属性,每个文件对应一个etag;另一个参数是If-Modified-Since,也就是响应头中的Last-Modified属性,带着这两个参数去检验缓存是否真的过期,如果没有过期,则服务器会给浏览器返回一个304状态码,表示缓存没有过期,可以使用旧缓存。
      • etag的作用
        • 有时候编辑了文件,但是没有修改,但是last-modified属性的时间就会改变,导致服务器会重新发送资源,但是etag的出现就完美的避免了这个问题,他是文件的唯一标识

    缓存位置:

    • 内存缓存Memory-Cache
    • 离线缓存Service-Worker
    • 磁盘缓存Disk-Cache
    • 推送缓存Push-Cache

    面试官:tcp 和udp有什么区别⭐⭐⭐⭐⭐

    • 连接方面

      • tcp面向连接,udp不需要连接
        • tcp需要三次握手四次挥手请求连接
    • 可靠性

      • tcp是可靠传输;一旦传输过程中丢包的话会进行重传
      • udp是不可靠传输,但会最大努力交付
    • 工作效率

      • UDP实时性高,比TCP工作效率高
        • 因为不需要建立连接,更不需要复杂的握手挥手以及复杂的算法,也没有重传机制
    • 是否支持多对多

      • TCP是点对点的
      • UDP支持一对一,一对多,多对多
    • 首部大小

      • tcp首部占20字节
      • udp首部占8字节

    面试官:从浏览器输入url后都经历了什么⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐具重要!

    • 先进行DNS域名解析,先查看本地hosts文件,查看有没有当前域名对应的ip地址,若有直接发起请求,没有的话会在本地域名服务器去查找,该查找属于递归查找,如果本地域名服务器没查找到,会从根域名服务器查找,该过程属于迭代查找,根域名会告诉你从哪个与服务器查找,最后查找到对应的ip地址后把对应规则保存到本地的hosts文件中。
    • 如果想加速以上及之后的http请求过程的话可以使用缓存服务器CDN,CDN过程如下:
      • 用户输入url地址后,本地DNS会解析url地址,不过会把最终解析权交给CNAME指向的CDN的DNS服务器
      • CDN的DNS服务器会返回给浏览器一个全局负载均衡IP
      • 用户会根据全局负载均衡IP去请求全局负载均衡服务器
      • 全局负载均衡服务器会根据用户的IP地址,url地址,会告诉用户一个区域负载均衡设备,让用户去请求它。
      • 区域负载均衡服务器会为用户选择一个离用户较近的最优的缓存服务器,并把ip地址给到用户
      • 用户想缓存服务器发送请求,如果请求不到想要的资源的话,会一层层向上一级查找,知道查找到为止。
    • 进行http请求,三次握手四次挥手建立断开连接
    • 服务器处理,可能返回304也可能返回200
      • 返回304说明客户端缓存可用,直接使用客户端缓存即可,该过程属于协商缓存
      • 返回200的话会同时返回对应的数据
    • 客户端自上而下执行代码
      • 其中遇到CSS加载的时候,CSS不会阻塞DOM树的解析,但是会阻塞DOM树的渲染,并且CSS会阻塞下面的JS的执行
      • 然后是JS加载,JS加载会影响DOM的解析,之所以会影响,是因为JS可能会删除添加节点,如果先解析后加载的话,DOM树还得重新解析,性能比较差。如果不想阻塞DOM树的解析的话,可以给script添加一个defer或者async的标签。
        • defer:不会阻塞DOM解析,等DOM解析完之后在运行,在DOMContentloaed之前
        • async: 不会阻塞DOM解析,等该资源下载完成之后立刻运行
      • 进行DOM渲染和Render树渲染
        • 获取html并解析为Dom树
        • 解析css并形成一个cssom(css树)
        • 将cssom和dom合并成渲染树(render树)
        • 进行布局(layout)
        • 进行绘制(painting)
        • 回流重绘
          • 回流必将引起重绘,重绘不一定引起回流

    滑动窗口和拥塞窗口有什么区别⭐⭐⭐

    解析TCP之滑动窗口(动画演示)
    以动画的形式解释滑动窗口,

    • 滑动窗口
      • 发送窗口永远小于或等于接收窗口,发送窗口的大小取决于接收窗口的大小
      • 控制流量来保证TCP的可靠传输(不控制流量的话可能会溢出)
      • 发送方的数据分为
        • 1已发送,接收到ACK的
        • 2已发送,未接收到ACK的
        • 3未发送,但允许发送的
        • 4未发送,但不允许发送的
        • 2和3表示发送窗口
      • 接收方
        • 1.已接收
        • 2.未接受但准备接受
        • 3.未接受不准备接受
    • 拥塞窗口
      • 防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
      • 是一个全局性的过程
      • 方法
        • 慢开始、拥塞避免、快重传、快恢复

    什么是CDN?⭐⭐⭐⭐

    关于 cdn、回源等问题一网打尽

    1.首先访问本地的 DNS ,如果没有命中,继续递归或者迭代查找,直到命中拿到对应的 IP 地址。

    2.拿到对应的 IP 地址之后服务器端发送请求到目的地址。注意这里返回的不直接是 cdn 服务器的 IP 地址,而是全局负载均衡系统的 IP 地址

    4.全局负载均衡系统会根据客户端的 IP地址和请求的 url 和相应的区域负载均衡系统通信

    5.区域负载均衡系统拿着这两个东西获取距离客户端最近且有相应资源的cdn 缓存服务器的地址,返回给全局负载均衡系统

    6.全局负载均衡系统返回确定的 cdn 缓存服务器的地址给客户端。

    7.客户端请求缓存服务器上的文件

    什么是xss?什么是csrf?⭐⭐⭐⭐⭐

    • xss脚本注入
      • 不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本(可能是js、hmtl代码块等)。
      • 防御
        • 编码:对用户输入的数据进行HTML Entity 编码。把字符转换成 转义字符。Encode的作用是将$var等一些字符进行转化,使得浏览器在最终输出结果上是一样的。
        • 过滤:移除用户输入的和事件相关的属性。
    • csrf跨域请求伪造
      • 在未退出A网站的前提下访问B,B使用A的cookie去访问服务器
      • 防御:token,每次用户提交表单时需要带上token(伪造者访问不到),如果token不合法,则服务器拒绝请求

    OWASP top10 (10项最严重的Web应用程序安全风险列表)都有哪些?⭐⭐⭐

    • SQL注入

      • 在输入框里输入sql命令
    • 失效的身份验证

      • 拿到别人的cookie来向服务端发起请求,就可以做到登陆的目的
    • 敏感数据泄露

      • 明文传输状态下可能被抓包拦截,这时候就造成数据泄露
        • 想做到抓包,比如在网吧,共享一个猫上网,这时候抓包就可行,方法网上一搜一大把
      • 不过此风险大部分网站都能得到很好的解决,https或者md5加密都可以
    • XML 外部实体

    • 失效的访问控制

    • 安全配置错误

    • XSS

    • 不安全的反序列化

    • 使用含有已知漏洞的组件

    • 不足的日志记录和监控

    怎么样?计算机网络是不是没有想象中的那么难,如果你没看过瘾的话,推荐你这篇文章:【长文】前端需要了解的计算机网络知识
    是不是得感激我一下【手动滑稽】

    谢谢

    面试官:什么是回流 什么是重绘?⭐⭐⭐⭐⭐

    • 回流
      • render树中一部分或全部元素需要改变尺寸、布局、或着需要隐藏而需要重新构建,这个过程叫做回流
      • 回流必将引起重绘
    • 重绘
      • render树中一部分元素改变,而不影响布局的,只影响外观的,比如颜色。该过程叫做重绘
    • 页面至少经历一次回流和重绘(第一次加载的时候)

    杂项

    事件冒泡和事件捕捉有什么区别⭐⭐⭐⭐⭐

    • 事件冒泡
      • 在addEventListener中的第三属性设置为false(默认)
      • 从下至上(儿子至祖宗)执行
    • 事件捕捉
      • 在addEventListener中的第三属性设置为true
      • 从上至下(祖宗到儿子)执行

    什么是防抖?什么是节流?手写一个⭐⭐⭐⭐⭐

    • 防抖
      • n秒后在执行该事件,若在n秒内被重复触发,则重新计时
    • 节流
      • n秒内只运行一次,若在n秒内重复触发,只有一次生效

     

    函数柯里化原理⭐⭐⭐⭐⭐

    什么是requestAnimationFrame?⭐⭐⭐⭐

    • requestAnimationFrame请求数据帧可以用做动画执行

    • 可以自己决定什么时机调用该回调函数

    • 能保证每次频幕刷新的时候只被执行一次

    • 页面被隐藏或者最小化的时候暂停执行,返回窗口继续执行,有效节省CPU

    • <span style="color:#000000"><code class="language-js">    <span style="color:#c678dd">var</span> s <span style="color:#669900">=</span> <span style="color:#98c379">0</span>
          <span style="color:#c678dd">function</span> <span style="color:#61aeee">f</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
            s<span style="color:#669900">++</span>
            console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span>s<span style="color:#999999">)</span><span style="color:#999999">;</span>
            <span style="color:#c678dd">if</span> <span style="color:#999999">(</span>s <span style="color:#669900"><</span> <span style="color:#98c379">999</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
              window<span style="color:#999999">.</span><span style="color:#61aeee">requestAnimationFrame</span><span style="color:#999999">(</span>f<span style="color:#999999">)</span>
            <span style="color:#999999">}</span>
          <span style="color:#999999">}</span>
          window<span style="color:#999999">.</span><span style="color:#61aeee">requestAnimationFrame</span><span style="color:#999999">(</span>f<span style="color:#999999">)</span>
      </code></span>

    js常见的设计模式⭐⭐⭐⭐⭐

    • 单例模式、工厂模式、构造函数模式、发布订阅者模式、迭代器模式、代理模式

    • 单例模式

      • 不管创建多少个对象都只有一个实例

      • <span style="color:#000000"><code class="language-js">    <span style="color:#c678dd">var</span> Single <span style="color:#669900">=</span> <span style="color:#999999">(</span><span style="color:#c678dd">function</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
              <span style="color:#c678dd">var</span> instance <span style="color:#669900">=</span> <span style="color:#c678dd">null</span>
              <span style="color:#c678dd">function</span> <span style="color:#61aeee">Single</span><span style="color:#999999">(</span>name<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>name <span style="color:#669900">=</span> name
              <span style="color:#999999">}</span>
              <span style="color:#c678dd">return</span> <span style="color:#c678dd">function</span> <span style="color:#999999">(</span>name<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                <span style="color:#c678dd">if</span> <span style="color:#999999">(</span><span style="color:#669900">!</span>instance<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                  instance <span style="color:#669900">=</span> <span style="color:#c678dd">new</span> Single<span style="color:#999999">(</span><span style="color:#999999">)</span>
                <span style="color:#999999">}</span>
                <span style="color:#c678dd">return</span> instance
              <span style="color:#999999">}</span>
            <span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">(</span><span style="color:#999999">)</span>
        
            <span style="color:#c678dd">var</span> oA <span style="color:#669900">=</span> <span style="color:#c678dd">new</span> Single<span style="color:#999999">(</span><span style="color:#669900">'hi'</span><span style="color:#999999">)</span>
            <span style="color:#c678dd">var</span> oB <span style="color:#669900">=</span> <span style="color:#c678dd">new</span> Single<span style="color:#999999">(</span><span style="color:#669900">'hello'</span><span style="color:#999999">)</span>
            console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span>oA<span style="color:#999999">)</span><span style="color:#999999">;</span>
            console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span>oB<span style="color:#999999">)</span><span style="color:#999999">;</span>
            console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span>oB <span style="color:#669900">===</span> oA<span style="color:#999999">)</span><span style="color:#999999">;</span>
        </code></span>
    • 工厂模式

      • 代替new创建一个对象,且这个对象想工厂制作一样,批量制作属性相同的实例对象(指向不同)

      • <span style="color:#000000"><code class="language-js">    <span style="color:#c678dd">function</span> <span style="color:#61aeee">Animal</span><span style="color:#999999">(</span>o<span style="color:#999999">)</span> <span style="color:#999999">{</span>
              <span style="color:#c678dd">var</span> instance <span style="color:#669900">=</span> <span style="color:#c678dd">new</span> Object<span style="color:#999999">(</span><span style="color:#999999">)</span>
              instance<span style="color:#999999">.</span>name <span style="color:#669900">=</span> o<span style="color:#999999">.</span>name
              instance<span style="color:#999999">.</span>age <span style="color:#669900">=</span> o<span style="color:#999999">.</span>age
              instance<span style="color:#999999">.</span><span style="color:#61aeee">getAnimal</span> <span style="color:#669900">=</span> <span style="color:#c678dd">function</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
                <span style="color:#c678dd">return</span> <span style="color:#669900">"name:"</span> <span style="color:#669900">+</span> instance<span style="color:#999999">.</span>name <span style="color:#669900">+</span> <span style="color:#669900">" age:"</span> <span style="color:#669900">+</span> instance<span style="color:#999999">.</span>age
              <span style="color:#999999">}</span>
              <span style="color:#c678dd">return</span> instance
            <span style="color:#999999">}</span>
        
            <span style="color:#c678dd">var</span> cat <span style="color:#669900">=</span> <span style="color:#61aeee">Animal</span><span style="color:#999999">(</span><span style="color:#999999">{</span>name<span style="color:#999999">:</span><span style="color:#669900">"cat"</span><span style="color:#999999">,</span> age<span style="color:#999999">:</span><span style="color:#98c379">3</span><span style="color:#999999">}</span><span style="color:#999999">)</span>
            console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span>cat<span style="color:#999999">)</span><span style="color:#999999">;</span>
        </code></span>
    • 构造函数模式

    • 发布订阅者模式

      • <span style="color:#000000"><code class="language-js">    <span style="color:#c678dd">class</span> Watcher <span style="color:#999999">{</span>
              <span style="color:#5c6370">// name模拟使用属性的地方</span>
              <span style="color:#61aeee">constructor</span><span style="color:#999999">(</span>name<span style="color:#999999">,</span> cb<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>name <span style="color:#669900">=</span> name
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>cb <span style="color:#669900">=</span> cb
              <span style="color:#999999">}</span>
              <span style="color:#61aeee">update</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span><span style="color:#5c6370">//更新</span>
                console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span><span style="color:#c678dd">this</span><span style="color:#999999">.</span>name <span style="color:#669900">+</span> <span style="color:#669900">"更新了"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span><span style="color:#61aeee">cb</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#5c6370">//做出更新回调</span>
              <span style="color:#999999">}</span>
            <span style="color:#999999">}</span>
        
            <span style="color:#c678dd">class</span> Dep <span style="color:#999999">{</span><span style="color:#5c6370">//依赖收集器</span>
              <span style="color:#61aeee">constructor</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>subs <span style="color:#669900">=</span> <span style="color:#999999">[</span><span style="color:#999999">]</span>
              <span style="color:#999999">}</span>
              <span style="color:#61aeee">addSubs</span><span style="color:#999999">(</span>watcher<span style="color:#999999">)</span> <span style="color:#999999">{</span>
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>subs<span style="color:#999999">.</span><span style="color:#61aeee">push</span><span style="color:#999999">(</span>watcher<span style="color:#999999">)</span>
              <span style="color:#999999">}</span>
              <span style="color:#61aeee">notify</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span><span style="color:#5c6370">//通知每一个观察者做出更新</span>
                <span style="color:#c678dd">this</span><span style="color:#999999">.</span>subs<span style="color:#999999">.</span><span style="color:#61aeee">forEach</span><span style="color:#999999">(</span>w <span style="color:#669900">=></span> <span style="color:#999999">{</span>
                  w<span style="color:#999999">.</span><span style="color:#61aeee">update</span><span style="color:#999999">(</span><span style="color:#999999">)</span>
                <span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
              <span style="color:#999999">}</span>
            <span style="color:#999999">}</span>
        
            <span style="color:#5c6370">// 假如现在用到age的有三个地方</span>
            <span style="color:#c678dd">var</span> w1 <span style="color:#669900">=</span> <span style="color:#c678dd">new</span> Watcher<span style="color:#999999">(</span><span style="color:#669900">"我{{age}}了"</span><span style="color:#999999">,</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#669900">=></span> <span style="color:#999999">{</span> console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span><span style="color:#669900">"更新age"</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#999999">}</span><span style="color:#999999">)</span>
            <span style="color:#c678dd">var</span> w2 <span style="color:#669900">=</span> <span style="color:#c678dd">new</span> Watcher<span style="color:#999999">(</span><span style="color:#669900">"v-model:age"</span><span style="color:#999999">,</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#669900">=></span> <span style="color:#999999">{</span> console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span><span style="color:#669900">"更新age"</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#999999">}</span><span style="color:#999999">)</span>
            <span style="color:#c678dd">var</span> w3 <span style="color:#669900">=</span> <span style="color:#c678dd">new</span> Watcher<span style="color:#999999">(</span><span style="color:#669900">"I am {{age}} years old"</span><span style="color:#999999">,</span> <span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#669900">=></span> <span style="color:#999999">{</span> console<span style="color:#999999">.</span><span style="color:#61aeee">log</span><span style="color:#999999">(</span><span style="color:#669900">"更新age"</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#999999">}</span><span style="color:#999999">)</span>
        
            <span style="color:#c678dd">var</span> dep <span style="color:#669900">=</span> <span style="color:#c678dd">new</span> Dep<span style="color:#999999">(</span><span style="color:#999999">)</span>
            dep<span style="color:#999999">.</span><span style="color:#61aeee">addSubs</span><span style="color:#999999">(</span>w1<span style="color:#999999">)</span>
            dep<span style="color:#999999">.</span><span style="color:#61aeee">addSubs</span><span style="color:#999999">(</span>w2<span style="color:#999999">)</span>
            dep<span style="color:#999999">.</span><span style="color:#61aeee">addSubs</span><span style="color:#999999">(</span>w3<span style="color:#999999">)</span>
        
        
            <span style="color:#5c6370">// 在Object.defineProperty 中的 set中运行</span>
            dep<span style="color:#999999">.</span><span style="color:#61aeee">notify</span><span style="color:#999999">(</span><span style="color:#999999">)</span>
        </code></span>
    • 代理模式

    • 迭代器模式

    JS性能优化的方式⭐⭐⭐⭐⭐

    • 垃圾回收
    • 闭包中的对象清楚
    • 防抖节流
    • 分批加载(setInterval,加载10000个节点)
    • 事件委托
    • 少用with
    • requestAnimationFrame的使用
    • script标签中的defer和async
    • CDN

    Vue

    Vue双向绑定

    数据劫持: vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调

    阐述一下你所理解的MVVM响应式原理⭐⭐⭐⭐⭐

    vue是采用数据劫持配合发布者-订阅者的模式的方式,通过Object.defineProperty()来劫持各个属性的getter和setter,在数据变动时,发布消息给依赖收集器(dep中的subs),去通知(notify)观察者,做出对应的回调函数,去更新视图

    MVVM作为绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer,Compile之间的通信桥路,达到数据变化=>视图更新;视图交互变化=>数据model变更的双向绑定效果。

    杂乱笔记

    • data中每一个数据都绑定一个Dep,这个Dep中都存有所有用到该数据的观察者

    • 当数据改变时,发布消息给dep(依赖收集器),去通知每一个观察者。做出对应的回调函数

    •  

    面试官:说说vue的生命周期⭐⭐⭐⭐⭐

    • beforeCreate
      • 创建之前,此时还没有data和Method
    • Created
      • 创建完成,此时data和Method可以使用了
      • 在Created之后beforeMount之前如果没有el选项的话那么此时生命周期结束,停止编译,如果有则继续
    • beforeMount
      • 在渲染之前
    • mounted
      • 页面已经渲染完成,并且vm实例中已经添加完$el了,已经替换掉那些DOM元素了(双括号中的变量),这个时候可以操作DOM了(但是是获取不了元素的高度等属性的,如果想要获取,需要使用nextTick()
    • beforeUpdate
      • data改变后,对应的组件重新渲染之前
    • updated
      • data改变后,对应的组件重新渲染完成
    • beforeDestory
      • 在实例销毁之前,此时实例仍然可以使用
    • destoryed
      • 实例销毁后

    面试官:vue中父子组件的生命周期⭐⭐⭐⭐⭐

    • 父子组件的生命周期是一个嵌套的过程
    • 渲染的过程
      • beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
    • 子组件更新过程
      • beforeUpdate->子beforeUpdate->子updated->父updated
    • 父组件更新过程
      • beforeUpdate->父updated
    • 销毁过程
      • beforeDestroy->子beforeDestroy->子destroyed->父destroyed

    Vue中的nextTick⭐⭐⭐⭐⭐

    • nextTick

      • 解释
        • nextTick:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
      • 应用
        • 想要在Vue生命周期函数中的created()操作DOM可以使用Vue.nextTick()回调函数
        • 在数据改变后要执行的操作,而这个操作需要等数据改变后而改变DOM结构的时候才进行操作,需要用到nextTick

    面试官:computed和watch的区别⭐⭐⭐⭐⭐

    • computed
      • 计算属性,依赖其他属性,当其他属性改变的时候下一次获取computed值时也会改变,computed的值会有缓存
    • watch
      • 类似于数据改变后的回调
      • 如果想深度监听的话,后面加一个deep:true
      • 如果想监听完立马运行的话,后面加一个immediate:true

    面试官:Vue优化方式⭐⭐⭐⭐⭐

    • v-if 和v-show

    • 使用Object.freeze()方式冻结data中的属性,从而阻止数据劫持

    • 组件销毁的时候会断开所有与实例联系,但是除了addEventListener,所以当一个组件销毁的时候需要手动去removeEventListener

    • 图片懒加载

    • 路由懒加载

    • 为减少重新渲染和创建dom节点的时间,采用虚拟dom

    面试官:Vue-router的模式⭐⭐⭐⭐⭐

    • hash模式
      • 利用onhashchange事件实现前端路由,利用url中的hash来模拟一个hash,以保证url改变时,页面不会重新加载。
    • history模式
      • 利用pushstate和replacestate来将url替换但不刷新,但是有一个致命点就是,一旦刷新的话,就会可能404,因为没有当前的真正路径,要想解决这一问题需要后端配合,将不存在的路径重定向到入口文件。

    面试官:MVC与MVVM有什么区别⭐⭐⭐⭐⭐

    哎呀呀,这个要参考的就多了。
    mvc和mvvm的区别
    基于Vue实现一个简易MVVM
    不好意思!耽误你的十分钟,让MVVM原理还给你

    • MVC
      • Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据
      • View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
      • Controller(控制器)是应用程序中处理用户交互的部分
        • 通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据

    diff算法⭐⭐⭐⭐⭐

    • diff算法是指对新旧虚拟节点进行对比,并返回一个patch对象,用来存储两个节点不同的地方,最后利用patch记录的消息局部更新DOM

    虚拟DOM的优缺点⭐⭐⭐⭐⭐

    • 缺点
      • 首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢
    • 优点
      • 减少了dom操作,减少了回流与重绘
      • 保证性能的下限,虽说性能不是最佳,但是它具备局部更新的能力,所以大部分时候还是比正常的DOM性能高很多的

    Vue的Key的作用 ⭐⭐⭐⭐

    • key
      • key主要用在虚拟Dom算法中,每个虚拟节点VNode有一个唯一标识Key,通过对比新旧节点的key来判断节点是否改变,用key就可以大大提高渲染效率,这个key类似于缓存中的etag。

    Vue组件之间的通信方式⭐⭐⭐⭐⭐

    • 子组件设置props + 父组件设置v-bind:/:

      • 父传子
    • 子组件的$emit + 父组件设置v-on/@

      • 子传父
    • 任意组件通信,新建一个空的全局Vue对象,利用e m i t 发 送 , emit发送,emit发送,on接收

      • 传说中的$bus

      • 任意组件

      • <span style="color:#000000"><code class="language-js">    Vue<span style="color:#999999">.</span>prototype<span style="color:#999999">.</span>Event<span style="color:#669900">=</span><span style="color:#c678dd">new</span> Vue<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
        	
        
            Event<span style="color:#999999">.</span><span style="color:#61aeee">$emit</span><span style="color:#999999">(</span>事件名<span style="color:#999999">,</span>数据<span style="color:#999999">)</span><span style="color:#999999">;</span>
            Event<span style="color:#999999">.</span><span style="color:#61aeee">$on</span><span style="color:#999999">(</span>事件名<span style="color:#999999">,</span>data <span style="color:#669900">=></span> <span style="color:#999999">{</span><span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
        </code></span>
    • Vuex

      • 里面的属性有:
        • state
          • 存储数据的
          • 获取数据最好推荐使用getters
          • 硬要使用的话可以用MapState, 先引用,放在compute中...mapState(['方法名','方法名'])
        • getters
          • 获取数据的
          • this.$store.getters.xxx
          • 也可使用mapGetters 先引用,放在compute中,...mapGetters(['方法名','方法名'])
        • mutations
          • 同步操作数据的
          • this.$store.commit(“方法名”,数据)
          • 也可使用mapMutations ,使用方法和以上一样
        • actions
          • 异步操作数据的
          • this.$store.dispatch(“方法名”,数据)
          • 也可使用mapActions ,使用方法和以上一样
        • modules
          • 板块,里面可以放多个vuex
    • 父组件通过v-bind:/:传值,子组件通过this.$attrs获取

      • 父传子
      • 当子组件没有设置props的时候可以使用
      • this.$attrs获取到的是一个对象(所有父组件传过来的集合)
    • 祖先组件使用provide提供数据,子孙组件通过inject注入数据

    • p a r e n t / parent/parent/children

    • refs—$ref

    • 还有一个,这个网上没有,我自己认为的,我觉得挺对的,slot-scope,本身父组件使用slot插槽是无法获取子组件的数据的,但是使用了slot-scope就可以获取到子组件的数据(拥有了子组件的作用域)

    Vue-router有哪几种钩子函数⭐⭐⭐⭐⭐

    • beforeEach
      • 参数有
        • to(Route路由对象)
        • from(Route路由对象)
        • next(function函数) 一定要调用才能进行下一步
    • afterEach
    • beforeRouterLeave

    Webpack

    webpack常用的几个对象及解释⭐⭐⭐⭐

    • entry 入口文件

    • output 输出文件

      • 一般配合node的path模块使用

        • <span style="color:#000000"><code class="language-js">    <span style="color:#5c6370">// 入口文件</span>
              entry<span style="color:#999999">:</span><span style="color:#669900">"./src/index.js"</span><span style="color:#999999">,</span>
              output<span style="color:#999999">:</span><span style="color:#999999">{</span>
                  <span style="color:#5c6370">// 输出文件名称</span>
                  filename<span style="color:#999999">:</span><span style="color:#669900">"bundle.js"</span><span style="color:#999999">,</span>
                  <span style="color:#5c6370">// 输出的路径(绝对路径)</span>
                  path<span style="color:#999999">:</span>path<span style="color:#999999">.</span><span style="color:#61aeee">resolve</span><span style="color:#999999">(</span>__dirname<span style="color:#999999">,</span><span style="color:#669900">"dist"</span><span style="color:#999999">)</span> <span style="color:#5c6370">//利用node模块的path 绝对路径</span>
              <span style="color:#999999">}</span><span style="color:#999999">,</span>
              <span style="color:#5c6370">// 设置模式</span>
              mode<span style="color:#999999">:</span><span style="color:#669900">"development"</span>
          </code></span>
    • mode 设计模式

    • module(loader)

      • 里面有一个rules数组对某种格式的文件进行转换处理(转换规则)

      • use数组解析顺序是从下到上逆序执行的

      •  
    • plugin

      • 插件配置

      •  
    • devServer

      • 热更新

      •  
    • resolve

      • 配置路径规则

      • alias 别名

      •  
    • babel(ES6转ES5)

      • 下载插件babel-loader,在module(loader)中配置

    loader和plugin的区别是什么?⭐⭐⭐

    • loader
      • loader是用来解析非js文件的,因为Webpack原生只能解析js文件,如果想把那些文件一并打包的话,就需要用到loader,loader使webpack具有了解析非js文件的能力
    • plugin
      • 用来给webpack扩展功能的,可以加载许多插件

    CSS/HTML

    flex布局⭐⭐⭐⭐⭐

    这个我就不例举了,看看阮一峰老师的文章叭!Flex 布局教程

    grid布局⭐⭐⭐⭐

    同样是阮一峰老师的,CSS Grid 网格布局教程

    常见的行内元素和块级元素都有哪些?⭐⭐⭐⭐⭐

    • 行内元素 inline
      • 不能设置宽高,不能自动换行
      • span、input、img、textarea、label、select
    • 块级元素block
      • 可以设置宽高,会自动换行
      • p、h1/h2/h3/h4/h5、div、ul、li、table
    • inline-block
      • 可以设置宽高,会自动换行

    请说明px,em,rem,vw,vh,rpx等单位的特性⭐⭐⭐⭐⭐

    • px
      • 像素
    • em
      • 当前元素的字体大小
    • rem
      • 根元素字体大小
    • vw
      • 100vw是总宽度
    • vh
      • 100vh是总高度
    • rpx
      • 750rpx是总宽度

    常见的替换元素和非替换元素?⭐⭐

    • 替换元素
      • 是指若标签的属性可以改变标签的显示方式就是替换元素,比如input的type属性不同会有不同的展现,img的src等
      • img、input、iframe
    • 非替换元素
      • div、span、p

    first-of-type和first-child有什么区别⭐⭐⭐⭐

    • first-of-type
      • 匹配的是从第一个子元素开始数,匹配到的那个的第一个元素
    • first-child
      • 必须是第一个子元素

    doctype标签和meta标签⭐⭐⭐⭐⭐

    • doctype
      • 告诉浏览器以什么样的文档规范解析文档
      • 标准模式和兼容模式
        • 标准模式 ->正常,排版和js运作模式都是以最高标准运行
        • 兼容模式->非正常

    script标签中defer和async都表示了什么⭐⭐⭐⭐⭐

    • 众所周知script会阻塞页面的加载,如果我们要是引用外部js,假如这个外部js请求很久的话就难免出现空白页问题,好在官方为我们提供了defer和async

    • defer

      • <span style="color:#000000"><code class="language-html"><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"><</span>script</span> <span style="color:#d19a66">src</span><span style="color:#669900"><span style="color:#999999">=</span><span style="color:#999999">"</span>d.js<span style="color:#999999">"</span></span> <span style="color:#d19a66">defer</span><span style="color:#999999">></span></span><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"></</span>script</span><span style="color:#999999">></span></span>
        <span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"><</span>script</span> <span style="color:#d19a66">src</span><span style="color:#669900"><span style="color:#999999">=</span><span style="color:#999999">"</span>e.js<span style="color:#999999">"</span></span> <span style="color:#d19a66">defer</span><span style="color:#999999">></span></span><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"></</span>script</span><span style="color:#999999">></span></span>
        </code></span>
        • 1
        • 2
      • 不会阻止页面解析,并行下载对应的js文件

      • 下载完之后不会执行

      • 等所有其他脚本加载完之后,在DOMContentLoaded事件之前执行对应d.jse.js

    • async

      • <span style="color:#000000"><code class="language-html"><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"><</span>script</span> <span style="color:#d19a66">src</span><span style="color:#669900"><span style="color:#999999">=</span><span style="color:#999999">"</span>b.js<span style="color:#999999">"</span></span> <span style="color:#d19a66">async</span><span style="color:#999999">></span></span><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"></</span>script</span><span style="color:#999999">></span></span>
        <span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"><</span>script</span> <span style="color:#d19a66">src</span><span style="color:#669900"><span style="color:#999999">=</span><span style="color:#999999">"</span>c.js<span style="color:#999999">"</span></span> <span style="color:#d19a66">async</span><span style="color:#999999">></span></span><span style="color:#e06c75"><span style="color:#e06c75"><span style="color:#999999"></</span>script</span><span style="color:#999999">></span></span>
        </code></span>
        • 1
        • 2
      • 不会阻止DOM解析,并行下载对应的js文件

      • 下载完之后立即执行

    • 补充DOMContentLoaded事件

      • 是等HTML文档完全加载完和解析完之后运行的事件
      • load事件之前。
      • 不用等样式表、图像等完成加载

    什么是BFC?⭐⭐⭐⭐⭐

    • BFC是一个独立渲染区域,它丝毫不会影响到外部元素
    • BFC特性
      • 同一个BFC下margin会重叠
      • 计算BFC高度时会算上浮动元素
      • BFC不会影响到外部元素
      • BFC内部元素是垂直排列的
      • BFC区域不会与float元素重叠
    • 如何创建BFC
      • position设为absolute或者fixed
      • float不为none
      • overflow设置为hidden
      • display设置为inline-block或者inline-table或flex

    如何清除浮动⭐⭐⭐⭐⭐

    • 额外标签clear:both

      •  
    • 利用BFC

      • overflow:hidden

      •  
    • 使用after(推荐)

      •  

    什么是DOM事件流?什么是事件委托⭐⭐⭐⭐⭐

    • DOM事件流
      • 分为三个阶段
        • 捕获阶段
        • 目标阶段
        • 冒泡阶段
      • 在addeventListener()的第三个参数(useCapture)设为true,就会在捕获阶段运行,默认是false冒泡
    • 事件委托
      • 利用冒泡原理(子向父一层层穿透),把事件绑定到父元素中,以实现事件委托

    link标签和import标签的区别⭐⭐⭐⭐

    • link属于html,而@import属于css
    • 页面被加载时,link会同时被加载,而@import引用的css会等到页面加载结束后加载。
    • link是html标签,因此没有兼容性,而@import只有IE5以上才能识别。
    • link方式样式的权重高于@import的。

     

    算法

    这里推荐一个排序算法的动画网站,应该是一个国外团队做的,Sorting Algorithms

    冒泡算法排序⭐⭐⭐⭐⭐

    快速排序⭐⭐⭐⭐⭐

    插入排序⭐⭐⭐⭐

    是否回文⭐⭐⭐⭐⭐

    正则表达式,千分位分隔符⭐⭐⭐⭐

    数组去重⭐⭐⭐⭐⭐

    斐波那契数列⭐⭐⭐⭐⭐

    数组去重的方式⭐⭐⭐⭐⭐

    git

    git的常用命令⭐⭐⭐⭐⭐

    commit之后撤回
    git reset soft HEAD^
    分支
    git branch xx 创建分支
    git checkout xx切换分支
    添加
    git add .
    git push
    git commit -m

     

    在这里插入图片描述

    git常用命令与常见面试题总结

     

    展开全文
  • 2021年最新Web前端面试题精选大全及答案

    万次阅读 多人点赞 2021-01-07 11:53:44
    1.网络中使用最多的图片格式有哪些 JPEG,GIF,PNG,最流行的是jpeg格式,可以把文件压缩到最小 在ps以jpeg格式存储时,提供11级压缩级别 2.请简述css盒子模型 一个css盒子从外到内可以分成四个部分:margin...

    目录

    HTML、CSS相关

    Javascript相关

    三者的异同

    Vue相关

    55.Vue路由懒加载(按需加载路由)

    React相关

    react 生命周期函数

    ******为什么虚拟 dom 会提高性能?(必考)

    (组件的)状态(state)和属性(props)之间有何不同

    shouldComponentUpdate 是做什么的

    react diff 原理

    何为受控组件

    调用 super(props) 的目的是什么

    React 中构建组件的方式

    小程序相关的

    其他

    企业中的项目流程

    奇葩问题


    HTML、CSS相关

    1.网络中使用最多的图片格式有哪些

    JPEG,GIF,PNG,最流行的是jpeg格式,可以把文件压缩到最小 在ps以jpeg格式存储时,提供11级压缩级别

    2.请简述css盒子模型

    https://bkimg.cdn.bcebos.com/pic/a9d3fd1f4134970a37cf81a69fcad1c8a6865dfe?x-bce-process=image/resize,m_lfit,w_268,limit_1/format,f_jpg

    一个css盒子从外到内可以分成四个部分:margin(外边距),border(边框),padding(内边距),content(内容)

    默认情况下,盒子的width和height属性只是设置content(内容)的宽和高

    盒子真正的宽应该是:内容宽度+左右填充+左右边距+左右边框

    盒子真正的高应该是:内容高度+上下填充+上下边距+上下边框

    3.视频/音频标签的使用

    视频:<video src=””></video>

    视频标签属性:

    src 需要播放的视频地址

    width/height 设置播放视频的宽高,和img标签的宽高属性一样

    autoplay 是否自动播放

    controls 是否显示控制条

    poster 没有播放之前显示的展位图片

    loop 是否循环播放

    perload 预加载视频(缓存)与autoplay相冲突,设置了autoplay属性,perload属性会失效。

    muted 静音模式

    音频: 音频属性和视频属性差不多,不过宽高和poster属性不能用

    <audio>

    <source src=”” type=””>

    </audio>

    4.HTML5新增的内容有哪些

    新增语义化标签

    新增表单类型

    表单元素

    表单属性

    表单事件

    多媒体标签

    5.Html5 新增的语义化标签有哪些

    语义化标签优点:

    1.提升可访问性 2.seo 3.结构清晰,利于维护

    Header页面头部 main页面主要内容 footer页面底部

    Nav导航栏 aside侧边栏 article加载页面一块独立内容

    Section相当于div  figure加载独立内容(上图下字) figcaption  figure的标题

    Hgroup标题组合标签 mark高亮显示 dialog 加载对话框标签(必须配合open属性)

    Embed加载插件的标签 video加载视频 audio加载音频(支持格式ogg,mp3,wav)

    6.Css3新增的特性

    边框:

    border-radius添加圆角边框       

    border-shadow:给框添加阴影 (水平位移,垂直位移,模糊半径,阴影尺寸,阴影颜色,insetr(内/外部阴影))

    border-image:设置边框图像

    border-image-source 边框图片的路径

    border-image-slice 图片边框向内偏移

    border-image-width 图片边框的宽度

    border-image-outset 边框图像区域超出边框的量

    border-image-repeat 图像边框是否平铺(repeat平铺 round铺满 stretch 拉伸)

    背景:

    Background-size 背景图片尺寸

    Background-origin规定background-position属性相对于什么位置定位

    Background-clip 规定背景的绘制区域(padding-box,border-box,content-box)

    渐变:

    Linear-gradient()线性渐变

    Radial-gradient()径向渐变

    文本效果:

    Word-break:定义如何换行

    Word-wrap:允许长的内容可以自动换行

    Text-overflow:指定当文本溢出包含它的元素,应该干啥

    Text-shadow:文字阴影(水平位移,垂直位移,模糊半径,阴影颜色)

    转换:

    Transform 应用于2D3D转换,可以将元素旋转,缩放,移动,倾斜

    Transform-origin 可以更改元素转换的位置,(改变xyz轴)

    Transform-style 指定嵌套元素怎么样在三位空间中呈现

    2D转换方法:

    rotate旋转 translate(x,y)指定元素在二维空间的位移 scale(n)定义缩放转换

    3D转换方法:

    Perspective(n)为3D转换 translate rotate scale

    过渡:

    Transition-property过渡属性名

    Transition-duration 完成过渡效果需要花费的时间

    Transition-timing-function 指定切换效果的速度

    Transition-delay 指定什么时候开始切换效果

    动画:animation

    Animation-name 为@keyframes动画名称

    animation-duration 动画需要花费的时间

    animation-timing-function 动画如何完成一个周期

    animation-delay 动画启动前的延迟间隔

    animation-iteration-count 动画播放次数

    animation-direction 是否轮流反向播放动画

    7.清除浮动的方式有哪些?请说出各自的优点

    高度塌陷:当所有的子元素浮动的时候,且父元素没有设置高度,这时候父元素就会产生高度塌陷。

    清除浮动方式1:给父元素单独定义高度

    优点:快速简单,代码少 缺点:无法进行响应式布局

    清除浮动方式2:父级定义overflow:hidden;zoom:1(针对ie6的兼容)

    优点:简单快速、代码少,兼容性较高 缺点:超出部分被隐藏,布局时要注意

    清除浮动方式3:在浮动元素后面加一个空标签,clear:both;height:0;overflow:hidden

    优点:简单快速、代码少,兼容性较高。

    缺点:增加空标签,不利于页面优化

    清除浮动方式4:父级定义overflow:auto

    优点:简单,代码少,兼容性好

    缺点:内部宽高超过父级div时,会出现滚动条

    清除浮动方式5:万能清除法:

    给塌陷的元素添加伪对象

    .father:after{

             Content:“随便写”;

             Clear:both;

             display:block;

             Height:0;

             Overflow:hidden;

             Visibility:hidden

    }

    优点:写法固定,兼容性高        缺点:代码多

    8.定位的属性值有何区别

    Position有四个属性值:relative absolute fixed static

    Relative相对定位 不脱离文档流,相对于自身定位

    Absolute 绝对定位,脱离文档流 相对于父级定位

    Fixed 固定定位,脱离文档流,相对于浏览器窗口定位

    Static 默认值,元素出现在正常的流中

    9.子元素如何在父元素中居中

    水平居中:

    1.子父元素宽度固定,子元素设置margin:auto,并且子元素不能设置浮动,否则居中失效

    2.子父元素宽度固定,父元素设置text-align:center,子元素设置display:inline-block,并且子元素不能设置浮动,否则居中失效

    水平垂直居中:

    1. 子元素相对于父元素绝对定位,子元素top,left设置50%,子元素margin-top和margin-left减去各自宽高的一半
    2. 子元素相对于父元素绝对定位,子元素上下左右全为0,然后设置子元素margin:auto
    3. 父元素设置display:table-cell vertical-align:middle,子元素设置margin:auto
    4. 子元素相对定位,子元素top,left值为50%,transform:translate(-50%,-50%)
    5. 子元素相对父元素绝对定位,子元素top,left值为50%,transform:translate(-50%,-50%)
    6. 父元素设置弹性盒子,

    display:flex; justfy-content:center ;align-item:center; justfy-content:center

    10.Border-box与content-box的区别?

    Content-box 标准盒模型 width不包括padding和border

    Border-box 怪异盒模型width包括padding和border

    11.如何让元素垂直居中?

    1).设置子元素和父元素的行高一样

    2).子元素设置为行内块,再加vertical-align:middle

    3).已知父元素高度,子元素相对定位,通过transform:translateY(-50%)

    4).不知道父元素高度,子绝父相,子元素top:50%,transform:translateY(-50%)

    5).创建一个隐藏节点,让隐藏节点的height为剩余高度的一半

    6).给父元素display:table,子元素display:table-cell,vertical-align:middle

    7).给父元素添加伪元素

    8).弹性盒,父元素display:flex,子元素align-self:center

    12.如何让chrome浏览器显示小于12px的文字?

    本来添加谷歌私有属性 -webkit-text-size-adjust:none,现在-webkit-transform:scale()

    13.Css选择器有哪些,那些属性可以继承,优先级如何计算?Css3新增的伪类有哪些?

    Css2选择器:元素选择器,id选择器,群组选择器,类选择器,*通配符选择器,后代选择器

    Css2伪类选择器:a:link/visited/hover/active

    Css3选择器:空格 >  +相邻兄弟选择器  ~通用选择器(查找后面所有)

    结构伪类选择器:

    查找第几个nth-child(n)

    查找同一类型第几个nth-of-type

    查找唯一类型 only-of-type

    属性选择器:根据标签属性查找 [attr=value]

    : root 查找根元素html标签

    : empty 查赵空标签

    目标伪类选择器:(表单)

    :enabled 查找可以使用的标签

    :disabled 查找禁止使用的标签

    :checked 查找被选中的标签

    伪元素选择器 ::selection设置选中文本内容的高亮显示(只能用于背景色和文本颜色)

    否定伪类选择器 not()

    语言伪类选择器 lang(取值)

    优先级(权重):

    元素选择器1

    伪元素选择器1

    class选择器10

    伪类选择器10

    属性选择器10

    Id选择器100

    内联样式的权重1000

    包含选择器权重为权重之和

    继承样式权重为0

    那些属性可以继承:

    Css继承特性主要是文本方面

    所有元素可继承:visibility和cursor

    块级元素可继承:text-indent和text-align

    列表元素可继承:list-style,list-style-type,list-style-position,list-style-image

    内联元素可继承:letter-spacing,word-spacing,line-height,color,font,font-family,font-size

    Font-style,font-variant,font-weight,text-decoration,text-transform,direction

    字母间距 段落间距  行高   字体颜色 字体种类 字体大小 字体样式  字体粗细 小型大写字母文本 文本修饰 转换不同元素中的文本 文本方向

    14.网页中有大量图片加载很慢 你有什么办法进行优化?

    1.图片懒加载,在图片未可视区域加一个滚动条事件,判断图片位置与浏览器顶端和页面的距离,如果前者小鱼后者,优先加载

    2.使用图片预加载技术,将当前展示图片的前一张和后一张优先下载

    3.使用csssprite或者svgsprite

    15.行内元素/块级元素有哪些?

    行内元素:相邻的行内元素会排列在同一行,不会独占一行 设置宽高无效 span

    块级元素:会独占一行 可以设置宽高等属性div

    可变元素:根据上下文预警决定该元素为块元素还是内联元素

    块级元素:div h1-h6 hr p ul ol table address blockquote dir from menu

    行内元素:a br I em img input select span sub sup u textarea

    可变元素:button del iframe ins

    16.浏览器的标准模式和怪异模式区别?

    标准模式:浏览器按照W3C标准解析执行代码

    怪异模式:浏览器根据自己的方式解析执行代码,因为不同浏览器解析执行方式不一样,所以叫怪异模式

    区别:

    1. 在怪异模式下,盒模型为怪异盒模型 而在标准模式下为标准盒子模型
    2. 图片元素的垂直对齐方式     对于行内元素和table-cell元素,标准模式下vertical-align属性默认值是baseline,而在怪异模式下,table单元格中的图片的vertical-align属性默认值是bottom,因此在图片底部会有几像素的空间
    3. 元素中的字体         css中font的属性都是可以继承的,怪异模式下,对于table元素,字体的某些元素不能从其他封装元素继承中得到,特别是font-size属性
    4. 内联元素的尺寸     标准模式下,non-replaced inline元素无法自定义大写,怪异模式下,定义元素的宽高会影响元素的尺寸
    5. 元素的百分比高度         当一个元素使用百分比高度时,在标准模式下,高度取决于内容变化,在怪异迷失下,百分比被准确应用
    6. 元素溢出的处理              标准模式下,overflow取值默认值为visible,在怪异模式下,这个溢出会被当做扩展box对待,就是元素的大小由内容决定,溢出不会裁剪,元素框自动调整,包含溢出内容

    17.Margin和padding在什么场合下使用

    Margin外边距 自身边框到另一个边框之间的距离

    Padding 内边距 自身边距到自身内容之间的距离

    当需要在border外侧添加空白时用margin,当需要在border内侧添加空白时用padding

    18.弹性盒子布局属性有那些请简述?

    Flex-direction:弹性容器中子元素排列方式(主轴排列方式)

    Flex-wrap:设置弹性盒子的子元素超出父容器时是否换行

    Flex-flow:是flex-direction和flex-wrap简写形式

    Align-item:设置弹性盒子元素在侧轴上的对齐方式

    Align-content:设置行对齐

    Justify-content:设置弹性盒子元素在主轴上的对齐方式

    19.怎么实现标签的禁用

    添加disabled属性

    20.Flex布局原理

    就是通过给父盒子添加flex属性,来控制子盒子的位置和排列方式

    21.Px,rem,em的区别

    Px,绝对长度单位,像素px是相对于显示器屏幕分辨率来说的

    em 相对长度单位,相对于当前对象内文本的字体尺寸

             em的值并不是固定的

             em会继承父级元素的字体大小(参考物是父元素的font-size)

             em中所有的字体都是相对于父元素的大小决定的

    rem 相对于html根元素的font-size

    1em=1rem=16px 在body中加入font-size:62.5% 这样直接就是原来的px数值除以10加上em就可以

    22.网页的三层结构有哪些

    结构(html或xhtm标记语言)表现(css样式表)行为(js)

    1. 请简述媒体查询

    媒体查询扩展了media属性, 就是根据不同的媒体类型设置不同的css样式,达到自适应的目的。

    1. Rem缺点

    比如:小说网站,屏幕越小的移动设备如果用了rem肯定文字就越小,就会导致看文章的时候特别费眼

    25.常见的兼容性一阶段内容中记几个

    26.垂直与水平居中的方式

    27.三栏布局方式两边固定中间自适应

    1. margin负值法:左右两栏均左浮动,左右两栏采用负的margin值。中间栏被宽度为100%的浮动元素包起来

    2. 自身浮动法:左栏左浮动,右栏右浮动,中间栏放最后

    3. 绝对定位法:左右两栏采用绝对定位,分别固定于页面的左右两侧,中间的主体栏用左右margin值撑开距离。

    4.flex  左右固定宽  中间flex:1

    5.网格布局

    6. table布局

    28.Doctype作用

    声明文档类型

    Javascript相关

    1.Js基本数据类型有哪些

    字符串String 数值Number  布尔boolean   null  undefined  对象 数组

    2.Ajax如何使用

    一个完整的AJAX请求包括五个步骤:

    1. 创建XMLHTTPRequest对象
    2. 使用open方法创建http请求,并设置请求地址

    xhr.open(get/post,url,async,true(异步),false(同步))经常使用前三个参数

    1. 设置发送的数据,用send发送请求
    2. 注册事件(给ajax设置事件)
    3. 获取响应并更新页面

    3.如何判断一个数据是NaN

    NaN 非数字 但是用typeof检测是number类型

    1. 利用NaN的定义  用typeof判断是否为number类型并且判断是否满足isnan
    2. 利用NaN是唯一一个不等于任何自身的特点 n!==n
    3. 利用ES6中提供的Object.is()方法(判断两个值是否相等)  n==nan
    4. Js中null与undefined区别

    相同点:用if判断时,两者都会被转换成false

    不同点:

    number转换的值不同 number(null)为0   number(undefined)为NaN

    Null表示一个值被定义了,但是这个值是空值

    Undefined 变量声明但未赋值

    5.闭包是什么?有什么特性?对页面会有什么影响

    闭包可以简单理解成:定义在一个函数内部的函数。其中一个内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

    特点:

    1.函数嵌套函数。

    2.函数内部可以引用外部的参数和变量。

    3.参数和变量不会被垃圾回收机制回收。

    使用:

    1.读取函数内部的变量;

     2.这些变量的值始终保持在内存中,不会在外层函数调用后被自动清除。

    优点:

    1:变量长期驻扎在内存中;

    2:避免全局变量的污染;

    3:私有成员的存在 ;

    缺点:会造成内存泄露

    6.Js中常见的内存泄漏:

    1.意外的全局变量

    2.被遗忘的计时器或回调函数

    3.脱离DOM的引用

    4.闭包

    7.事件委托是什么?如何确定事件源(Event.target  谁调用谁就是事件源)

    JS高程上讲:事件委托就是利用事件冒泡,只制定一个时间处理程序,就可以管理某一类型的所有事件。

    事件委托,称事件代理,是js中很常用的绑定事件的技巧,事件委托就是把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务,事件委托的原理是DOM元素的事件冒泡

    8.什么是事件冒泡?

    一个事件触发后,会在子元素和父元素之间传播,这种传播分为三个阶段,

    捕获阶段(从window对象传导到目标节点(从外到里),这个阶段不会响应任何事件),目标阶段,(在目标节点上触发),冒泡阶段(从目标节点传导回window对象(从里到外)),事件委托/事件代理就是利用事件冒泡的机制把里层需要响应的事件绑定到外层

    9.本地存储与cookie的区别

    Cookie 是小甜饼的意思。顾名思义,cookie 确实非常小,它的大小限制为4KB左右。它的主要用途有保存登录信息,比如你登录某个网站市场可以看到“记住密码”,这通常就是通过在 Cookie 中存入一段辨别用户身份的数据来实现的。

    localStorage

    localStorage 是 HTML5 标准中新加入的技术,它并不是什么划时代的新东西。早在 IE 6 时代,就有一个叫 userData 的东西用于本地存储,而当时考虑到浏览器兼容性,更通用的方案是使用 Flash。而如今,localStorage 被大多数浏览器所支持,如果你的网站需要支持 IE6+,那以 userData 作为你方案是种不错的选择。

    sessionStorage

    sessionStorage 与 localStorage 的接口类似,但保存数据的生命周期与 localStorage 不同。做过后端开发的同学应该知道 Session 这个词的意思,直译过来是“会话”。而 sessionStorage 是一个前端的概念,它只是可以将一部分数据在当前会话中保存下来,刷新页面数据依旧存在。但当页面关闭后,sessionStorage 中的数据就会被清空。

    三者的异同

    特性

    Cookie

    localStorage

    sessionStorage

    数据的生命期

    一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效

    除非被清除,否则永久保存

    仅在当前会话下有效,关闭页面或浏览器后被清除

    存放数据大小

    4K左右

    一般为5MB

    与服务器端通信

    每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题

    仅在客户端(即浏览器)中保存,不参与和服务器的通信

    易用性

    需要程序员自己封装,源生的Cookie接口不友好

    源生接口可以接受,亦可再次封装来对Object和Array有更好的支持

    10.ES6新特性

    const和let、模板字符串、箭头函数、函数的参数默认值、对象和数组解构、for...of 和 for...in、ES6中的类

    11.Let与var与const的区别

    Var声明的变量会挂载在window上,而let和const声明的变量不会

    Var声明的变量存在变量提升,let和const不存在变量提升

    同一作用域下var可以声明同名变量,let和const、不可以

    Let和const声明会形成块级作用域

    Let暂存死区

    Const一旦声明必须赋值,不能用null占位,声明后不能再修改,如果声明的是复合类型数据,可以修改属性

    12.数组方法有哪些请简述

    push() 从后面添加元素,返回值为添加完后的数组的长度

    arr.pop() 从后面删除元素,只能是一个,返回值是删除的元素

    arr.shift() 从前面删除元素,只能删除一个 返回值是删除的元素

    arr.unshift() 从前面添加元素, 返回值是添加完后的数组的长度

     arr.splice(i,n) 删除从i(索引值)开始之后的那个元素。返回值是删除的元素

    arr.concat() 连接两个数组 返回值为连接后的新数组

    str.split() 将字符串转化为数组

     arr.sort() 将数组进行排序,返回值是排好的数组,默认是按照最左边的数字进行排序,不是按照数字大小排序的

    arr.reverse() 将数组反转,返回值是反转后的数组

     arr.slice(start,end) 切去索引值start到索引值end的数组,不包含end索引的值,返回值是切出来的数组

     arr.forEach(callback) 遍历数组,无return  即使有return,也不会返回任何值,并且会影响原来的数组

     arr.map(callback) 映射数组(遍历数组),有return 返回一个新数组 。

     arr.filter(callback) 过滤数组,返回一个满足要求的数组 

    13.Json如何新增/删除键值对

    14.什么是面向对象请简述

    面向对象是一种思想,是基于面向过程而言的,就是说面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节;这种思想是将数据作为第一位,这是对数据一种优化,操作起来更加的方便,简化了过程。

    Js本身是没有class类型的,但是每个函数都有一个prototype属性,prototype指向一个对象,当函数作为构造函数时,prototype就起到类似于class的作用

    面向对象有三个特点:封装(隐藏对象的属性和实现细节,对外提供公共访问方式),

    继承(提高代码复用性,继承是多态的前提),多态(是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象)

    15.普通函数和构造函数的区别

    1.构造函数也是一个普通函数,创建方式和普通函数一样,但是构造函数习惯上首字母大写

    2.调用方式不一样,普通函数直接调用,构造函数要用关键字new来调用

    3.调用时,构造函数内部会创建一个新对象,就是实例,普通函数不会创建新对象

    4.构造函数内部的this指向实例,普通函数内部的this指向调用函数的对象(如果没有对象调用,默认为window)

    5.构造函数默认的返回值是创建的对象(也就是实例),普通函数的返回值由return语句决定

    6.构造函数的函数名与类名相同

    *****16.请简述原型/原型链/(原型)继承*****

    什么是原型:
        任何对象实例都有一个原型,也叫原型对象,这个原型对象由对象的内置属性_proto_指向它的构造函数的prototype指向的对象,即任何对象都是由一个构造函数创建的,但是不是每一个对象都有prototype,只有方法才有prototype。
    什么是原型链?
    原型链基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。我们知道,每个构造函数都有一个原型对象,每个原型对象都有一个指向构造函数的指针,而实例又包涵一个指向原型对象的内部指针。
        原型链的核心就是依赖对象的_proto_的指向,当自身不存在的属性时,就一层层的扒出创建对象的构造函数,直至到Object时,就没有_proto_指向了。
    因为_proto_实质找的是prototype,所以我们只要找这个链条上的构造函数的prototype。其中Object.prototype是没有_proto_属性的,它==null。

    每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含指向原型对象内部的指针。我们让原型对象(1)等于另一个原型对象的实例(2),
    此时原型对象(2)将包含一个指向原型对象(1)的指针,
    再让原型对象(2)的实例等于原型对象(3),如此层层递进就构成了实例和原型的链条,这就是原型链的概念

    每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数想指针(constructor),而实例对象都包含一个指向原型对象的内部指针(__proto__)。如果让原型对象等于另一个原型对象的实例,此时的原型对象将包含一个指向另一个原型的指针(__proto__),另一个原型也包含着一个指向另一个构造函数的指针(constructor)。假如另一个原型又是另一个类型的实例……这就构成了实例与原型的链条。也叫原型链
    原型继承是js的一种继承方式,原型链作为实现继承的主要方法,其基本思路是利用原型让一个引用类型继承另一个引用类型的属性和方法, 
    原型继承:利用原型中的成员可以被和其相关的对象共享这一特性,可以实现继承,这种实现继承的方式,就叫做原型继承.

    17.Promise的理解 

    一、什么是Promise?我们用Promise来解决什么问题?
    我们都知道,Promise是承诺的意思,承诺它过一段时间会给你一个结果。
    Promise 是一种解决异步编程的方案,相比回调函数事件更合理和更强大。
    从语法上讲,promise是一个对象,从它可以获取异步操作的消息;
    二、promise有三种状态:pending 初始状态也叫等待状态,fulfiled成功状态,rejected失败状态;状态一旦改变,就不会再变。创造promise实例后,它会立即执行。
    三、Promise的两个特点
    1、Promise对象的状态不受外界影响
    2、Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,
    四、Promise的三个缺点
    1)无法取消Promise,一旦新建它就会立即执行,无法中途取消
    2)如果不设置回调函数,Promise内部抛出的错误,不会反映到外部
    3)当处于pending(等待)状态时,无法得知目前进展到哪一个阶段,是刚刚开始还是即将完成

    promise是用来解决两个问题的:
    1.回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
    2.promise可以支持多并发的请求,获取并发请求中的数据
    这个promise可以解决异步的问题,本身不能说promise是异步的     

    19.请简述async的用法

    Async就是generation和promise的语法糖,async就是将generator的*换成async,将yiled换成await

    函数前必须加一个async,异步操作方法前加一个await关键字,意思就是等一下,执行完了再继续走,注意:await只能在async函数中运行,否则会报错

    Promise如果返回的是一个错误的结果,如果没有做异常处理,就会报错,所以用try..catch捕获一下异常就可以了

    20.. 一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

    分为4个步骤:

    1. 当发送一个 URL 请求时,不管这个 URL 是 Web 页面的 URL 还是 Web 页面上每个资源的 URL,浏览器都会开启一个线程来处理这个请求,同时在远程 DNS 服务器上启动一个 DNS 查询。这能使浏览器获得请求对应的 IP 地址。

    2. 浏览器与远程 Web 服务器通过 TCP 三次握手协商来建立一个 TCP/IP 连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在 浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,然后服务器响应并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。

    3. 一旦 TCP/IP 连接建立,浏览器会通过该连接向远程服务器发送 HTTP 的 GET 请求。远程服务器找到资源并使用 HTTP 响应返回该资源

    4. 此时,Web 服务器提供资源服务,客户端开始下载资源。

    jQuery相关的知识

    Css预处理sass less是什么?为什么使用他们

    Sass和less都是css预处理器,是css上的一种抽象层,是一种特殊的语法,最终会编译成css,less是一种动态样式语言,给css赋予了动态语言的特性,比如:变量,继承,嵌套。Less既可以在客户端运行,在可以在服务端运行(需要借助node)

    Js中.call()与.apply()区别

    apply:调用一个对象的一个方法,用另一个对象替换当前对象。

    call:调用一个对象的一个方法,用另一个对象替换当前对象。

    从定义中可以看出,call和apply都是调用一个对象的一个方法,用另一个对象替换当前对象。而不同之处在于传递的参数,apply最多只能有两个参数——新this对象和一个数组argArray,如果arg不是数组则会报错

    相同点:两个方法产生的作用是完全一样的。call, apply作用就是借用别人的方法来调用,就像调用自己的一样.

    不同点:方法传递的参数不同

    为什么会造成跨域/请简述同源策略

    出现跨域问题的原因:

    在前后端分离的模式下,前后端的域名是不一致的,此时就会发生跨域访问问题。在请求的过程中我们要想回去数据一般都是post/get请求,所以..跨域问题出现

    跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号(如存在)相同,则允许相互访问。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。

    同源策略 是由NetScape提出的一个著名的安全策略。所谓的同源,指的是协议,域名,端口相同。浏览器处于安全方面的考虑,只允许本域名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源。

    请输出三种减少页面加载时间的方式

    1. 优化图片 

    2. 图像格式的选择(GIF:提供的颜色较少,可用在一些对颜色要求不高的地方) 

    3. 优化CSS(压缩合并css,如 margin-top, margin-left...) 

    4. 网址后加斜杠(如www.campr.com/目录,会判断这个目录是什么文件类型,或者是目录。)  cdn托管

    5. 标明高度和宽度(如果浏览器没有找到这两个参数,它需要一边下载图片一边计算大小,如果图片很多,浏览器需要不断地调整页面。这不但影响速度,也影响浏览体验。 

    当浏览器知道了高度和宽度参数后,即使图片暂时无法显示,页面上也会腾出图片的空位,然后继续加载后面的内容。从而加载时间快了,浏览体验也更好了) 

    6. 减少http请求(合并文件,合并图片)

    This指向

    在JavaScript中,this通常指向的是我们正在执行的函数本身,或者是,指向该函数所属的对象。

    全局的this → 指向的是Window

    对象中的this → 指向其本身

    事件中this → 指向事件对象

    什么是jsonp工作原理是什么?他为什么不是真正的ajax

    Jsonp其实就是一个跨域解决方案。

    Js跨域请求数据是不可以的,但是js跨域请求js脚本是可以的

    所以可以把要请求的数据封装成一个js语句,做一个方法的调用。

    跨域请求js脚本可以得到此脚本。得到js脚本之后会立即执行。

    可以把数据做为参数传递到方法中。就可以获得数据。从而解决跨域问题。

    jsonp原理:(动态创建script标签,回调函数)

    浏览器在js请求中,是允许通过script标签的src跨域请求,可以在请求的结果中添加回调方法名,在请求页面中定义方法,就可获取到跨域请求的数据。

    为什么不是真正的 ajax?    

    1、ajax和jsonp这两种技术在调用方式上"看起来"很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;

    2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。

    3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。

    4、还有就是,jsonp是一种方式或者说非强制协议,如同ajax一样,它也不一定非要json格式来传递数据,如果你愿意,字符换也行,只不过这样不利于jsonp提供公开服务。

    请掌握2种以上数组去重的方式

    1. 使用indexof()方法
    2. 使用lastindexof()方法  和indexof方法一样  indexof从头部开始匹配  lastindexof从尾部匹配
    3. ES6的set结构  set不接受重复数据
    4.  使用sort方法先将原数组排序,然后与相邻的比较,如果不同则存入新数组
    5. 使用filiter和indexof方法
    6. 使用ES6 的set和扩展运算符
    7. 使用set和Array.from()方法             array.from可以将set结构转成数组
    8. 用splice和双层循环
    9. 使用includes方法

    深浅拷贝是什么如何实现?

    深拷贝:指针赋值,并且内容拷贝、                                                                浅拷贝:只是简单的指针赋值                                                                  数组浅拷贝: 如果是数组,可以使用数组的一些方法实现:slice(),concat()返回一个新数组的特性实现拷贝。用扩展运算符spread实现                                                                 数组深拷贝: JSON.parse(JSON.stringify())不仅适用于数组还适用于对象。不能拷贝函数,undefined,symbol。

    为什么js是弱类型语言

    弱类型语言实现相对于强类型语言来说的,在强类型语言中,变量类型有多种,比如int char float Boolean  不同类型相互转换有时需要强制转换,而jacascript只有一种类型var,为变量赋值时会自动判断类型并转换,所以是弱类型语言。

    怎么转换less为css

    1. 用node将less文件生成为css文件

    2.用webstorm自动生成

    echarts使用最多的是什么

    图表及图表组合

    For循环与map循环有什么区别

    For遍历对象自身的和继承可枚举的属性,也就是说会包括哪些原型链上的属性

    Map方法不会对空数组进行检测,map会返回一个新数组,不会对原数组产生影响

    请写出一个简单的类与继承

    创建类有三种:

    1. 使用function和this关键字
    2. 原型方法  用prototype和this关键字
    3. 使用object.create()方法构造

    继承有六种:原型继承        借用构造函数继承        组合继承        原型式继承    寄生式继承         寄生组合式继承

    同步与异步的区别/阻塞与非阻塞区别

    同步(阻塞的)

    异步(非阻塞)

    比如:同步,咱两在一起上班,到吃饭时间了,我去喊你一起吃饭,你很忙,我就坐着等你忙完再一起去吃饭

             异步,咱两在一起上班,到吃饭时间了,我去喊你一起吃饭,你很忙,我就先自己去吃了,你忙完了再去吃饭

    同步(阻塞)异步(非阻塞)这两个关注的是程序在等待调用结果时的状态

    重绘和回流是什么

    回流:当render tree中的一部分或者全部因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就叫回流,每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候一定会发生回流,因为要构建render tree

    在回流的时候,浏览器会使渲染树中收到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,这就是重绘

    render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,不会影响布局,就叫重绘

    http是什么?有什么特点

    http叫做超文本传输协议,是互联网应用最广泛的一种网络协议

    特点:基于请求-响应的模式   无状态保存   无连接

    HTTP协议和HTTPS区别

    1. http是超文本传输协议,信息是明文传输,https是具有安全性的ssl解密传输协议
    2. http和https连接方式完全不同,端口也不同,http是80,https是443
    3. http的连接很简单,是无状态的,https协议是由ssl+http协议构建的可进行加密传输,身份认证的网络协议,比http协议安全

    原型和继承,prototype,call和apply继承的区别(第一个参数是相同的,第二个的区别在哪)

    apply()接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。

    call()方法第一个参数与apply()方法相同,但传递给函数的参数必须列举出来。

    箭头函数与普通函数的区别

    1. 箭头函数是匿名函数,不能作为构造函数,不能使用new
    2. 箭头函数不能绑定arguments,要用rest参数解决
    3. 箭头函数没有原型属性
    4. 箭头函数的this永远指向其上下文的this,
    5. 箭头函数不能绑定this,会捕获其所在的上下文的this值,作为自己的this值

    什么是js内存泄露?

    内存泄漏是指一块被分配的内存既不能使用又不能回收,直到浏览器进程结束

    释放内存的方法:赋值为null

    你如何对网站的文件和资源进行优化?

    1、文件合并(目的是减少http请求)

    2、文件压缩(目的是直接减少文件下载的体积)

    3、使用cdn托管资源

    4、使用缓存

    5、gizp压缩你的js和css文件

    6、meta标签优化(title,description,keywords)、heading标签的优化、alt优化             7、反向链接,网站外链接优化

    请简述ajax的执行过程 以及常见的HTTP状态码

    100:这个状态码是告诉客户端应该继续发送请求,这个临时响应是用来通知客户端的,部分的请求服务器已经接受,但是客户端应继续发送求请求的剩余部分,如果请求已经完成,就忽略这个响应,而且服务器会在请求完成后向客户发送一个最终的结果

    200:这个是最常见的http状态码,表示服务器已经成功接受请求,并将返回客户端所请求的最终结果

    202:表示服务器已经接受了请求,但是还没有处理,而且这个请求最终会不会处理还不确定

    204:服务器成功处理了请求,但没有返回任何实体内容 ,可能会返回新的头部元信息

    301:客户端请求的网页已经永久移动到新的位置,当链接发生变化时,返回301代码告诉客户端链接的变化,客户端保存新的链接,并向新的链接发出请求,已返回请求结果

    404:请求失败,客户端请求的资源没有找到或者是不存在

    500:服务器遇到未知的错误,导致无法完成客户端当前的请求。

    503:服务器由于临时的服务器过载或者是维护,无法解决当前的请求

    预加载和懒加载的区别,预加载在什么时间加载合适

             预加载是指在页面加载完成之前,提前将所需资源下载,之后使用的时候从缓存中调用;懒加载是延迟加载,按照一定的条件或者需求等到满足条件的时候再加载对应的资源

    两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

    Jquery选择器有哪些

    一、基本选择器
    基本选择器是jQuery中最常用也是最简单的选择器,它通过元素的id、class和标签名等来查找DOM元素。
    1、ID选择器 #id
    描述:根据给定的id匹配一个元素, 返回单个元素(注:在网页中,id名称不能重复)
    示例:$("#test") 选取 id 为 test 的元素
    2、类选择器 .class
    描述:根据给定的类名匹配元素,返回元素集合
    示例:$(".test") 选取所有class为test的元素
    3、元素选择器 element
    描述:根据给定的元素名匹配元素,返回元素集合
    示例:$("p") 选取所有的<p>元素
    4、*
    描述:匹配所有元素,返回元素集合
    示例:$("*") 选取所有的元素
    5、selector1,selector2,...,selectorN
    描述:将每个选择器匹配到的元素合并后一起返回,返回合并后的元素集合
    示例:$("p,span,p.myClass") 选取所有<p>,<span>和class为myClass的<p>标签的元素集合
    二、层次选择器
    层次选择器根据层次关系获取特定元素。
    1、后代选择器
    示例:$("p span") 选取<p>元素里的所有的<span>元素(注:后代选择器选择父元素所有指定选择的元素,不管是儿子级,还是孙子级)
    2、子选择器 $("parent>child")
    示例:$("p>span") 选择<p>元素下的所有<span>元素 (注:子选择器只选择直属于父元素的子元素)
    3、同辈选择器 $("prev+next")
    描述:选取紧接在prev元素后的next元素,返回元素集合
    示例:$(".one+p") 选取class为one的下一个<p>同辈元素集合
    4、同辈选择器 $("prev~siblings")
    描述:选取prev元素后的所有siblings元素,返回元素集合
    示例:$("#two~p")选取id为two的元素后所有<p>同辈元素集合
    三、过滤选择器
    1>基本过滤选择器
    1、 :first
    描述:选取第一个元素,返回单个元素
    示例:$("p:first") 选取所有<p>元素中第一个<p>元素
    2、 :last
    描述:选取最后一个元素,返回单个元素
    示例:$("p:last") 选取所有<p>元素中最后一个<p>元素
    3、 :not(selector)
    描述:去除所有与给定选择器匹配的元素,返回元素集合
    示例:$("input:not(.myClass)") 选取class不是myClass的<input>元素
    4、 :even
    描述:选取索引是偶数的所有元素,索引从0开始,返回元素集合
    5、 :odd
    描述:选取索引是奇数的所有元素,索引从0开始,返回元素集合
    6、 :eq(index)
    描述:选取索引等于index的元素,索引从0开始,返回单个元素
    7、 :gt(index)
    描述:选取索引大于index的元素,索引从0开始,返回元素集合
    8、 :lt(index)
    描述:选取索引小于于index的元素,索引从0开始,返回元素集合
    9、 :focus
    描述:选取当前获取焦点的元素
    2>内容过滤选择器
    1、:contains(text)
    描述:选取含有文本内容为text的元素,返回元素集合
    示例:$("p:contains('我')") 选取含有文本“我”的元素
    2、:empty
    描述:选取不包含子元素或者文本元素的空元素,返回元素集合
    示例:$("p:empty") 选取不包含子元素或者文本元素的空<p>元素(<p></p>)
    3、:has(selector)
    描述:选取含有选择器所匹配的元素的元素,返回元素集合
    示例:$("p:has(p)") 选取含有<p>元素的<p>元素(<p><p/></p>)
    4、:parent
    描述:选取含有子元素或者文本的元素,返回元素集合
    示例:$("p:parent") 选取含有子元素或者文本元素的<p>元素(<p><p/></p>或者<p>文本</p>)
    3>可见性过滤选择器
    1、:hidden
    描述:选取所有不可见的元素,返回元素集合
    2、:visible
    描述:选取所有可见的元素,返回元素集合
    4>属性过滤选择器(返回元素集合)
    1、[attribute]
    示例:$("p[id]") 选取拥有id属性的p元素
    2、[attribute=value]
    示例:$("input[name=text]") 选取拥有name属性等于text的input元素
    3、[attribute!=value]
    示例:$("input[name!=text]") 选取拥有name属性不等于text的input元素
    4、[attribute^=value]
    示例:$("input[name^=text]") 选取拥有name属性以text开始的input元素
    5、[attribute$=value]
    示例:$("input[name$=text]") 选取拥有name属性以text结束的input元素
    6、[attribute*=value]
    示例:$("input[name*=text]") 选取拥有name属性含有text的input元素
    7、[attribute~=value]
    示例:$("input[class~=text]") 选取拥有class属性以空格分割的值中含有text的input元素
    8、[attribute1][attribute2][attributeN]
    描述:合并多个属性过滤选择器
    5>表单对象属性过滤选择器(返回元素集合)
    1、:enabled
    描述:选取所有可用元素
    2、:disabled
    描述:选取所有不可用元素
    3、:checked
    描述:选取所有被选中的元素(单选框,复选框)
    示例:$("input:checked") 选取所有被选中的<input>元素
    4、:selected
    描述:选取所有被选中的选项元素(下拉列表)
    示例:$("select option:selected") 选取所有被选中的选项元素

    Jquery插入节点的方法

    append()  向每个匹配的元素内部追加内容

    appendTo()  将所有匹配的元素追加到指定元素中,实际上,使用该方法是颠倒了常规的$(A).append(B)的操作 将A追加到B中

    prepend()  向每个匹配的元素内部前置内容

    prependTo()  将所有匹配的元素前置到指定的元素中。实际上,使用该方法是颠倒了常规的$(A).prepend(B)的操作,即不是将B前置到A中,而是将A前置到B中

    after()  在每个匹配的元素之后插入内容

    insertAfter()  将所有匹配的元素插入到指定元素的后面。实际上,使用该方法是颠倒了常规的$(A).after(B)的操作,即不是讲B插入到A后面,而是将A插入到B后面

    before()  在每个匹配的元素之前插入内容

    insertBefore()  将所有匹配的元素插入到指定的元素的前面。实际上,使用该方法是颠倒了常规的$(A).before(B)的操作,即不是将B插入到A前面,而是将A插入到B前面

    Js的函数节流和函数防抖的区别

    函数节流是指一定时间内js方法只执行一次。

    函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次

    函数节流是 声明一个变量当标志位,记录当前代码是否在执行,如果正在执行,取消这次方法执行,直接return,如果空闲,正常触发方法执行

    函数防抖是需要一个延时器来辅助实现,延迟执行需要执行的代码,如果方法多次触发,把上次记录的延迟执行代码用cleartimeout清除掉,重新开始,如果计时完毕,没有方法来访问触发,则执行代码

    Get和post不同

    Get是从服务器上获取数据,post是向服务器传送数据

    在客户端,get通过url提交数据,数据在url中可以看到,post方式,数据放在html header中提交

    安全性问题

    Get提交数据最多只能有1024字节,post没有限制

    什么是csrf攻击

    Csrf(跨站点请求伪造) 攻击者在用户已经登录目标网站之后,诱使用户访问一个攻击页面,利用目标网站对用户的信任,以用户身份再攻击页面对目标网站发起伪造用户操作的请求,达到攻击目的

    Js中手写一个深拷贝

    什么时候用深拷贝 /浅拷贝

    无论深浅,都是需要的,当深拷贝发生时通常表明存在着一个聚合关系,当浅拷贝发生时,通常表明存在着相识关系

    举个简单例子:当实现一个组合模式Composite  Pattern时通常都会实现深拷贝

    当实现一个观察者模式Observer  Pattern,时,就需要实现浅拷贝

    Vue相关

    1.Vue的核心是什么

    Vue是一套构建用户界面的渐进式自底向上增量开发的MVVM框架,vue的核心只关注视图层,

    核心思想:  

    数据驱动(视图的内容随着数据的改变而改变)

    组件化(可以增加代码的复用性,可维护性,可测试性,提高开发效率,方便重复使用,体现了高内聚低耦合)

    2.请简述你对vue的理解

    Vue是一套构建用户界面的渐进式的自底向上增量开发的MVVM框架,核心是关注视图层,vue的核心是为了解决数据的绑定问题,为了开发大型单页面应用和组件化,所以vue的核心思想是数据驱动和组件化,这里也说一下MVVM思想,MVVM思想是 模型  视图  vm是v和m连接的桥梁,当模型层数据修改时,VM层会检测到,并通知视图层进行相应修改

    3.请简述vue的单向数据流

    父级prop的更新会向下流动到子组件中,每次父组件发生更新,子组件所有的prop都会刷新为最新的值

    数据从父组件传递给子组件,只能单向绑定,子组件内部不能直接修改父组件传递过来的数据,(可以使用data和computed解决)

    1. Vue常用的修饰符有哪些

    修饰符:.lazy 改变后触发,光标离开input输入框的时候值才会改变

                       .number 将输出字符串转为number类型

                       .trim 自动过滤用户输入的首尾空格

    事件修饰符:

    .stop 阻止点击事件冒泡,相当于原生js中的event.stopPropagation()

    .prevent 防止执行预设的行为,相当于原生js中event.preventDefault()

    .capture 添加事件侦听器时使用事件捕获模式,就是谁有该事件修饰符,就先触发谁

    .self  只会触发自己范围内的事件,不包括子元素

    .once 只执行一次

    键盘修饰符:

    .enter 回车键          .tab 制表键             .esc返回键     .space 空格键

    .up向上键                .down 向下键        .left向左建    .right向右键

    系统修饰符:.ctrl .alt   .shift  .meta

    5.v-text与{{}}与v-html区别

    {{}} 将数据解析为纯文本,不能显示输出html

    v-html 可以渲染输出html

    v-text 将数据解析为纯文本,不能输出真正的html,与花括号的区别是在页面加载时不显示双花括号

    v-text 指令:

    作用:操作网页元素中的纯文本内容。{{}}是他的另外一种写法

    v-text与{{}}区别:

    v-text与{{}}等价,{{}}叫模板插值,v-text叫指令。

    有一点区别就是,在渲染的数据比较多的时候,可能会把大括号显示出来,俗称屏幕闪动:

    6.v-on可以绑定多个方法吗

    可以  如果绑定多个事件,可以用键值对的形式 事件类型:事件名

             如果绑定是多个相同事件,直接用逗号分隔就行

    7.Vue循环的key作用

    Key值的存在保证了唯一性,Vue在执行时,会对节点进行检查,如果没有key值,那么vue检查到这里有dom节点,就会对内容清空并赋新值,如果有key值存在,那么会对新老节点进行对比,比较两者key是否相同,进行调换位置或删除操作

    8.什么是计算属性

    计算属性是用来声明式的描述一个值依赖了其他的值,当它依赖的这个值发生改变时,就更新DOM

    当在模板中把数据绑定到一个计算属性上时,vue会在它依赖的任何值导致该计算属性改变时更新DOM

    每个计算属性都包括一个getter和setter,读取时触发getter,修改时触发setter

    1. Vue单页面的优缺点

    单页面spa

    优点:前后端分离  用户体验好 一个字  快  内容改变不需要重新加载整个页面

    缺点:不利于seo,  初次加载时耗长(浏览器一开始就要加载html  css js ,所有的页面内容都包含在主页面中) ,页面复杂度提高了,导航不可用

    1. Vuex是什么?怎么使用?在那种场景下使用

    Vuex是一个专为vue.js应用程序开发的状态管理模式,通过创建一个集中的数据存储,方便程序中的所有组件进行访问,简单来说 vuex就是vue的状态管理工具

    Vuex有五个属性 state  getters  mutations  actions  modules

    State就是数据源存放地,对应一般vue对象的data,state里面存放的数据是响应式的,state数据发生改变,对应这个数据的组件也会发生改变  用this.$store.state.xxx调用

    Getters 相当于store的计算属性,主要是对state中数据的过滤,用this.$store.getters.xxx调用

    Mutations 处理数据逻辑的方法全部放在mutations中,当触发事件想改变state数据的时候使用mutations,用this.$store.commit调用,给这个方法添加一个参数,就是mutation的载荷(payload

    Actions 异步操作数据,但是是通过mutation来操作 用this.$store.dispatch来触发,actions也支持载荷

    使用场景:组件之间的状态,登录状态,加入购物车,音乐播放

    Vuex使用流程:

    下载vuex 

    在src下创建store以及index.js

    引入vue和vuex, 使用vuex  ,导出实例对象

    在main.js中引入,在.vue文件中使用

    1. Vue中路由跳转方式(声明式/编程式)

    Vue中路由跳转有两种,分别是声明式和编程式

    用js方式进行跳转的叫编程式导航   this.$router.push()

    用router-link进行跳转的叫声明式   router-view 路由出口,路由模板显示的位置

    1. 路由中name属性有什么作用?
    1. 在router-link中使用name导航到对应路由
    2. 使用name导航的同时,给子路由传递参数

    12.vue跨域的解决方式

    1.后台更改header

    2.使用jq提供jsonp

    3.用http-proxy-middleware(配置代理服务器的中间件)

    13.Vue的生命周期请简述

    vue的生命周期就是vue实例创建到实例销毁的过程。期间会有8个钩子函数的调用。

    beforeCreate(创建实例)

    created(创建完成)、

    beforeMount(开始创建模板)

    mounted(创建完成)、

    beforeUpdate(开始更新)

    updated(更新完成)、

    beforeDestroy(开始销毁)

    destroyed(销毁完成)

    1. Vue生命周期的作用

    给了用户在不同阶段添加自己的代码的机会

    15.DOM渲染在那个生命周期阶段内完成

    DOM渲染在mounted周期中就已经完成

    1. Vue路由的实现

    前端路由就是更新视图但不请求页面,

    利用锚点完成切换,页面不会刷新

    官网推荐用vue-router.js来引入路由模块

    1. 定义路由组件
    2. 定义路由,使用component进行路由映射组件,用name导航到对应路由
    3. 创建router实例,传入routes配置
    4. 创建和挂载根实例
    5. 用router-link设置路由跳转

    17.Vue路由模式hashhistory,简单讲一下

             Hash模式地址栏中有#,history没有,history模式下刷新,会出现404情况,需要后台配置

    使用  JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值

    可以使用 hashchange 事件来监听 hash 值的变化

    HTML5 提供了 History API 来实现 URL 的变化。其中最主要的 API 有以下两个:history.pushState() 和 history.repalceState()。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录。

    18.Vue路由传参的两种方式,params和query方式与区别

    动态路由也可以叫路由传参,就是根据不同的选择在同一个组件渲染不同的内容

    用法上:query用path引入,params用name引入接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name

    url展示上:params类似于post,query类似于get,也就是安全问题,params传值相对更安全点,query通过url传参,刷新页面还在,params刷新页面不在了

    19.Vue数据绑定的几种方式

    1.单向绑定  双大括号 {{}}  html内字符串绑定

    2.v-bind绑定  html属性绑定

    3.双向绑定 v-model

    4.一次性绑定  v-once 依赖于v-model

    20.Vue注册一个全局组件

    Vue.componnet(“组件的名字”{对象   template <div>组建的内容</div>})

    21.Vue的路由钩子函数/路由守卫有哪些

    全局守卫:beforeEach(to,from,next)和afterEach(to,from)

    路由独享守卫:beforeEnter

    组件内的守卫:路由进入/更新/离开之前 beforeRouterEnter/update/leave

    22.Vue中如何进行动态路由设置?有哪些方式?怎么获取传递过来的数据?

    动态路由也可以叫路由传参,

    动态路由有query和prrams两种方式传参

    query用path引入,params用name引入,query用this.$route.query.name接收参数

    params用this.$route.params.name接收参数

    23.Elementui中的常用组件有哪些?请简述你经常使用的 并且他们的属性有哪些?

    Container布局容器 

    <el-container>外层容器

    <el-header>顶栏容器

    <el-aside>侧边栏容器

    <el-main>主要内容容器

    <el-footer>底栏容器

    Dropdown  下拉菜单

    <el-container split-buton> 下拉按钮   

    <el-container-menu> 下拉菜单   

    <el-container-item> 下拉项

    Table  表格

    Tabs  标签页

    Form  表单

    Pagination 分页

    Message  消息提示

    24.Vue-cli中如何自定义指令

    25.Vue中指令有哪些

    v-for:循环数组,对象,字符串,数字

    v-on:绑定事件监听

    v-bind:动态绑定一个或者多个属性

    v-model:表单控件或者组件上创建双向绑定

    v-if  v-else  v-else-if  条件渲染

    v-show  根据表达式真假,切换元素的display

    v-html 更新元素的innerhtml

    v-text 更新元素的textcontent

    v-pre 跳过这个元素和子元素的编译过程

    v-clock 这个指令保持在元素上知道关联实例结束编译

    v-once  只渲染一次

    26.Vue如何定义一个过滤器

    过滤器本质就是一个有参数有返回值的方法

    new Vue({

        filters:{

          myCurrency:function(myInput){

            return 处理后的数据

          }

        }

    })

    使用方法:<h1>{{表达式 | 过滤器}}</h1>

    过滤器高级用法:可以指定参数,告诉过滤器按照参数进行数据的过滤

    27.对vue 中keep-alive的理解

    概念:keep-alive是vue的内置组件,当它动态包裹组件时,会缓存不活动的组件实例,它自身不会渲染成一个DOM元素也不会出现在父组件链中

    作用:在组件切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间以及性能消耗,提高用户体验。

    生命周期函数:Activated在keep-alive组件激活时调用,deactivated在keep-alive组件停用时调用

    28.如何让组件中的css在当前组件生效

    在styled中加上scoped

    29.Vue生命周期一共几个阶段

    创建  加载   更新   销毁

    Beforecreate创建前

    Created   创建后

    Beforemount   加载前

    Mounted 加载后

    Beforeupdate 更新前

    Updated 更新后

    Beforedestroy 销毁前

    Destroyed  销毁后

    页面第一次加载会触发 beforecreate  created   beforemount   mounted

    DOM渲染在mounted周期中就已经完成

    30.Mvvm与mvc的区别

    Mvc模型视图控制器,视图是可以直接访问模型,所以,视图里面会包含模型信息,mvc关注的是模型不变,所以,在mvc中,模型不依赖视图,但是视图依赖模型

    Mvvm 模型  视图  和vm  vm是作为模型和视图的桥梁,当模型层数据改变,vm会检测到并通知视图层进行相应的修改

    31.Vue组件中的data为什么是函数

    Data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响

    如果是引用类型(对象),当多个组件共用一个数据源时,一处数据改变,所有的组件数据都会改变,所以要利用函数通过return返回对象的拷贝,(返回一个新数据),让每个实例都有自己的作用域,相互不影响。

    32.Vue双向绑定的原理

    Vue双向绑定就是:数据变化更新视图,视图变化更新数据

    Vue数据双向绑定是通过数据劫持观察者模式来实现的,

    数据劫持,object.defineproperty它的目的是:当给属性赋值的时候,程序可以感知到,就可以控制改变属性值

    观察者模式 当属性发生改变的时候,使用该数据的地方也发生改变

    33.Vue中组件怎么传值

    正向:父传子  父组件把要传递的数据绑定在属性上,发送,子组件通过props接收

    逆向:子传父        子组件通过this.$emit(自定义事件名,要发送的数据),父组件设置一个监听事件来接收,然后拿到数据

    兄弟:eventbus  中央事件总线

    通过Vuex

    34.Bootstrap的原理

    网格系统的实现原理,通过定义容器大小,平分12份,(24份或者32份),再调整内外边距,结合媒体查询,就成了强大的响应式网格系统。

    比如  row  col-xs-4

    36.如果一个组件在多个项目中使用怎么办

    37.槽口请简述

    大概分这几点,首先槽口(插槽)可以放什么内容?放在哪?什么作用?可以放任意内容,在子组件中使用,是为了将父组件中的子组件模板数据正常显示。

    具名插槽和匿名插槽,作用域插槽,说白了就是在组件上的属性,可以在组件元素内使用,

    可以在父组件中使用slot-scope从子组件获取数据

    38.Watch请简述

    Watch的作用是监控一个值的变化,并调用因为变化需要执行的方法

    39.Vant Ui请简述下

    轻量、可靠的移动端 Vue 组件库

    40.计算属性与watch区别

    Computed  watch   区别就是computed的缓存功能,当无关数据数据改变时,不会重新计算,直接使用缓存中的值。计算属性是用来声明式的描述一个值依赖了其他的值,当所依赖的值后者变量发生变化时,计算属性也跟着改变,

    Watch监听的是在data中定义的变量,当该变量变化时,会触发watch中的方法

    41.mvvm框架是什么?它和其它框架(jquery)的区别是什么?哪些场景适合?

    Mvvm和其他框架的区别是  vue数据驱动  通过数据来显示视图而不是节点操作

    适用于数据操作比较多的场景

    42.Vue首屏加载慢的原因,怎么解决的,白屏时间怎么检测,怎么解决白屏问题

    首屏加载慢的原因:

    第一次加载页面有很多组件数据需要渲染

    解决方法:

    1.路由懒加载  component:()=>import(“路由地址”)

    2.ui框架按需加载

    3.gzip压缩

    白屏时间检测:

    ????

    解决白屏问题:

    ①使用v-text渲染数据

    ②使用{{}}语法渲染数据,但是同时使用v-cloak指令(用来保持在元素上直到关联实例结束时候进行编译),v-cloak要放在什么位置呢,v-cloak并不需要添加到每个标签,只要在el挂载的标签上添加就可以

    43.Vue双数据绑定过程中,这边儿数据改变了怎么通知另一边改变

    数据劫持和观察者模式

    Vue数据双向绑定是通过数据劫持观察者模式来实现的,

    数据劫持,object.defineproperty它的目的是:当给属性赋值的时候,程序可以感知到,就可以控制属性值的有效范围,可以改变其他属性的值

    观察者模式它的目的是当属性发生改变的时候,使用该数据的地方也发生改变

    44.Vuex流程

    在vue组件里面,通过dispatch来触发actions提交修改数据的操作,然后通过actions的commit触发mutations来修改数据,mutations接收到commit的请求,就会自动通过mutate来修改state,最后由store触发每一个调用它的组件的更新

    45.Vuex怎么请求异步数据

    1.首先在state中创建变量

    2.然后在action中调用封装好的axios请求,异步接收数据,commit提交给mutations

    Mutations中改变state中的状态,将从action中获取到的值赋值给state

    46.Vuex中action如何提交给mutation的

    Action函数接收一个与store实例具有相同方法和属性的context对象,可以调用context.commit提交一个mutation,或者通过context.state和context.getters获取state和getters

    47.Route与router区别

    1.   router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性。

    2.route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等

    49.vuex的State特性是?

    State就是数据源的存放地

    State里面的数据是响应式的,state中的数据改变,对应这个数据的组件也会发生改变

    State通过mapstate把全局的state和getters映射到当前组件的计算属性中

    50.vuex的Getter特性是?

    Getter可以对state进行计算操作,它就是store的计算属性

    Getter可以在多组件之间复用

    如果一个状态只在一个组件内使用,可以不用getters

    51.vuex的Mutation特性是?

    更改vuex  store中修改状态的唯一办法就是提交mutation,可以在回调函数中修改store中的状态

    52.vuex的actions特性是?

    Action类似于mutation,不同的是 action提交的是mutation,不是直接变更状态,可以包含任意异步操作

    54.vuex的优势

    优点:解决了非父子组件的通信,减少了ajax请求次数,有些可以直接从state中获取

    缺点:刷新浏览器,vuex中的state会重新变为初始状态,解决办法是vuex-along,得配合计算属性和sessionstorage来实现

    55.Vue路由懒加载(按需加载路由)

    56.v-for与v-if优先级

    首先不要把v-if与v-for用在同一个元素上,原因:v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。

    v-for 比 v-if 具有更高的优先级

    请写出饿了么5个组件
    <el-alert>弹窗</el-alert>
    <el-dialog>对话</el-dialog>
    <el-calender>日历表</el-calender>
    <el-progress:percentage="0">进度条<el-progrees>
    <el-switch>开关</el-switch>

    React相关

    fetch VS ajax VS axios

    传统 Ajax 指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始js中,核心使用XMLHttpRequest对象,多个请求之间如果有先后关系的话,就会出现回调地狱。JQuery ajax 是对原生XHR的封装

    axios 是一个基于Promise ,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,

    fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。

    React事件处理---修改this指向

    方式1:通过bind方法进行原地绑定,从而改变this指向

    方式2:通过创建箭头函数

    方式3:在constructor中提前对事件进行绑定

    方式4:将事件调用的写法改为箭头函数的形式

    请简述你对react的理解

    React起源于facebook,react是一个用于构建用户界面的js库

    特点:

    声明式设计:react采用范式声明,开发者只需要声明显示内容,react就会自动完成

    高效: react通过对dom的模拟(也就是虚拟dom),最大限度的减少与dom的交互

    灵活: react可以和已知的库或者框架很好配合

    组件: 通过react构建组件,让代码更容易复用,能够很好应用在大型项目开发中,把页面功能拆分成小模块  每个小模块就是组件

    单向数据流:  react是单向数据流,数据通过props从父节点传递到子节点,如果父级的某个props改变了,react会重新渲染所有的子节点

    react组件之间的数据传递

    正向传值用props

    逆向传值用函数传值 通过事件调用函数传递

    同级传值用pubsub-js

    用pubsub.publish(事件名,数据)抛出数据

    用pubsub.subscribe(监听的事件,()=){})接收数据

    跨组件传递  用context  要使用context进行跨组件传值就需要使用createContext()方法,这个方法有两个对象  provider  生产者   Consumer 消费者

    Vue与react区别

    相同点:

    1. 都支持服务器渲染
    2. 都有虚拟dom,组件化开发,通过props参数进行父子组件数据的传递,都实现webcomponent规范
    3. 都是数据驱动视图
    4. 都有状态管理,react有redux,vue有vuex
    5. 都有支持native’的方案 react有react native  vue有weex

    不同点:

    1. react严格上只针对mvc的view层,vue是mvvm模式
    2. 虚拟dom不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个dom组件树,而react不同,当应用的状态被改变时,全部组件都会重新渲染,所以react中用shouldcomponentupdate这个生命周期的钩子函数来控制
    3. 组件写法不一样 ,react是jsx和inline style ,就是把html和css全写进js中,vue则是html,css ,js在同一个文件
    4. 数据绑定不一样,vue实现了数据双向绑定,react数据流动是单向的
    5. 在react中,state对象需要用setstate方法更新状态,在vue中,state对象不是必须的,数据由data属性在vue对象中管理

    请简述虚拟dom与diff算法

    虚拟DOM也就是常说的虚拟节点,它是通过js的object对象模拟DOM中的节点,然后再通过特定的渲染方法将其渲染成真实的DOM节点。

    频繁的操作DOM,或大量造成页面的重绘和回流

    Diff算法:把树形结构按照层级分解,只比较同级元素,给列表结构的每个单元添加唯一的key值,方便比较

    你对组件的理解

    可组合,可复用,可维护,可测试

    调用 setState 之后发生了什么?

    React在调用setstate后,react会将传入的参数对象和组件当前的状态合并,触发调和过程,

    在调和过程中,react会根据新的状态构建react元素树重新渲染整个UI界面,在得到元素树之后,react会自动计算新老节点的差异,根据差异对界面进行最小化重新渲染

    react 生命周期函数

    componentWillMount  组件渲染之前调用

    componentDidMount  在第一次渲染之后调用

    componentWillReceiveProps  在组件接收到一个新的props时调用

    shouldComponentUpdate  判断组件是否更新html

    componentWillupdate  组件即将更新html时调用

    componentDidupdate  在组件完成更新后立即调用

    componentWillUnmount  在组件移除之前调用

    ******为什么虚拟 dom 会提高性能?(必考)

    虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能

    (组件的)状态(state)和属性(props)之间有何不同

    State与props区别

    Props是一个从外部传进组件的参数,主要作用就是父组件向子组件传递数据,但是props对于使用它的组件来说是只读的,一旦赋值不能修改,只能通过外部组件主动传入新的props来重新渲染子组件

    State 一个组件的显示形态可以由数据状态和外部参数决定,外部参数是props,数据状态就是state,首先,在组件初始化的时候,用this.state给组件设定一个初始的state,在第一次渲染的时候就会用这个数据来渲染组件,state不同于props一点时,state可以修改,通过this.setState()方法来修改state

    shouldComponentUpdate 是做什么的

    这个react生命周期钩子函数是来解决这个问题:

    在更新数据的时候用setState修改整个数据,数据变了之后,遍历的时候所有内容都要被重新渲染,数据量少还好,数据量大就会严重影响性能

    解决办法:

    1.shouldcomponentupdate 在渲染前进行判断组件是否更新,更新了再渲染

    2.purecomponent(纯组件)省去了虚拟dom生成和对比的过程  在类组件中使用

    3.react.memo() 类似于纯组件 在无状态组件中使用

    react diff 原理

    它是基于三个策略:

    1. tree diff  web UI中dom节点跨层级的移动操作特别少,可以忽略不计
    2. component diff 拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件会生成不同的树形结构
    3. element diff 对于同一层级的一组子节点,他们可以通过唯一的id进行区分

    何为受控组件

    React负责渲染表单的组件,值是来自于state控制的,输入表单元素称为受控组件

    调用 super(props) 的目的是什么

    Super()调用父类的构造方法,有super,组件才有自己的this,在组件全局中都可以使用this,如果只是constructor而不执行super,之后的this都是错的,super继承父组件的this

    React 中构建组件的方式

    自定义组件:函数组件或者无状态组件  组件首字母大写

    类组件:一个类组件必须实现一个render方法,这个方法必须返回一个jsx元素,要用一个外层的元素把所有内容包裹起来

    小程序相关的

    小程序的优势

    无需下载安装,直接使用,运行速度快,项目搭建迅速,短小精悍,每个app源代码不超过2mb

    小程序的页面构成(4个文件)

    Index.js   index.json   index.wxml    index.wxss

    小程序的生命周期

    Onload   onready    onshow    onhide   onunload  

    Onpulldownrefresh    onreachbottom    onshareappmessage

    小程序如何请求数据

    用request

    如何提高小程序的首屏加载时间

    提前请求:异步数据数据请求不需要等待页面渲染完成

    利用缓存:利用storage API对异步请求数据进行缓存,二次启动时先利用缓存数据渲染页面,再进行后台更新

    避免白屏:先展示页面骨架和基础内容

    及时反馈:及时地对需要用户等待的交互操作给出反馈,避免用户以为小程序没有响应

    性能优化:避免不当使用setdata和onpagescroll

    请简述你经常使用的小程序的组件

    View  icon   text  image   swiper   navigator  input   button   map

    Wxss与css的区别请简述

    Wxss新增了尺寸单位 rpx

    提供了全局样式和局部样式

    Wxss仅支持部分css选择器  id’  class  元素等

    小程序如何实现响应式

    Rpx

    怎么优化小程序

    提高页面加载速度

    用户行为预测

    减少默认data的大小

    组件化方案

    自主获知自己的服务器

    小程序如何显示用户头像与用户名

    传统接口wx.getuserinfo 目前可以用,需要用户授权,使用时会有官方发提示,这个方法需要升级

    最新方法:open-data标签,使用这个标签可以不用用户授权直接获取头像和用户名,

    可以在button中将opendata作为属性写进去,写个点击事件就直接获取到了

    请谈谈小程序的双向绑定和vue的异同?

    Vue双向绑定是通过数据拦截和观察者模式,通过this.value获取值,小程序是通过触发表单元素绑定的方法,在方法中用this.setData({key:value})来取值

    小程序中传参是怎么传的

    vue类比介绍

    说一下微信小程序的适配问题

    小程序页面间有哪些传递数据的方法?

    你是怎么封装微信小程序的数据请求的

    说一下微信小程序的适配问题

    小程序跳转页面的方式

    微信小程序如何跳转到其他小程序

    小程序加载过慢的解决方式

    其他

    Typescript是什么 请简述?

    Typescript 与javascript 的优势?

    Webpack与gulp区别

    Gulp是一种能够优化前端开发流程的工具,webpack是一种模块化的解决方案 (grunt)

    请简述webpack中的loaders与plugin的区别

    什么是loaders,loaders是文件加载器,能够加载资源文件,并对这些文件进行处理,例如,编译,压缩等,最终一起打包到指定文件中。

    什么是plugin,在webpack运行的生命周期会有许多事件,plugin可以监听这些事件

    区别:加载器是用来加载文件的,webpack本身只能加载js文件(内置babel-loader),加载其他文件就需要安装别的loader,比如:css-loader  file-loader

    Plugin是扩展webpack功能的,通过plugin  ,webpack可以实现loader不能完成的复杂功能

    怎么提升页面性能?性能优化有哪些?

    Node使用来做什么的

    能够在服务器端运行JavaScript

    Webpack:入口,出口,加载器,插件

    说一下webpack的打包原理

    Webpack是把项目当做一个整体,通过给定一个主文件,webpack将从这个主文件开始找到项目中所有依赖的文件,使用loaders类处理,最后打包成一个或者多个浏览器可识别的js文件

    Commonjs ES6模块区别?

    1. common模块是拷贝,可以修改值,es6模块是引用,只读状态,不能修改值
    2. commonjs模块是运行时加载,es6模块是编译时输出接口

    Git如何使用/常用指令有哪些

    你们后台用的是什么技术

    你的项目比较小为什么还是用vue全家桶

    请简述你在项目中使用的ui框架

    前端性能优化的方式越多越好

    什么是cors

    说一下对websocked的理解

    Websocked是一种双向通信协议,在建立连接后,websocked服务器和浏览器都能主动向对方发送或者接收数据,websocked需要类似于tcp的客户端和服务器通过握手连接,连接成功后才能互相通信

    后台传递过来的数据是那些

    谈谈Ajaxfetchaxios的区别

    企业中的项目流程

    1.WEB前端项目开发流程

    项目需求分析

    这个环节是由项目经理完成,项目经理首先和客户进行交流,了解客户的需求,然后分析项目的可行性,如果项目可以被实现,项目经理写出项目需求文档交给设计师完成后续的开发。

    页面设计/项目选型

    这个环节主要是UI设计师参与,UI设计师根据产品需求分析文档,对产品的整体美术风格、交互设计、界面结构、操作流程等做出设计。负责项目中各种交互界面、图标、LOGO、按钮等相关元素的设计与制作。并且确定使用技术

    编码

    这个部分由程序员来实现。(程序员分为WEB前端开发工程师和后台开发工程师。前端开发人员主要做我们可以在网页上看的见的页面,后台就做一些我们看不见的管理系统以及功能的实现。)程序员根据UI设计师的设计,用编码来完成整个项目的各个功能。

    测试

    这部分由程序测试员来完成。程序测试员主要就是测试寻找程序还存在的bug,一般来说刚编码完成的程序都是存在问题的,就需要测试人员反复不断的测试并将存在问题的测试结果交给编码人员进行bug的修复。等到几乎所有bug修复完成,这个项目差不多就可以上线了。

    维护

    程序的维护是整个项目的最后一个阶段,但也是耗时最多,成本最高最高的的一个阶段。程序的维护包括程序上线后后续bug的修复和程序版本的更新。

    1. 更换接口域名

    就是在开发的时候调用的后台接口是后台测试的接口  项目上线后要把请求的接口替换成上线的域名

    1. 经常使用的工具

    代码管理平台:github 码云

    需求发布平台:钉钉任务,禅道

    Ui交互平台:蓝湖

    产品原型工具:axure

    企业邮箱:阿里 腾讯企业邮箱

    后台语言:java php python(西安不多)

    4大公司和小公司开发的区别

    大型外包公司更加流程化,人员多,沟通少,项目交付后不需要自己维护,采用瀑布开发模式(以文档为主)

    小型公司:人少 需求经常改变 沟通方便 采用敏捷开发(快速推出v1版本 ,之后迭代)

    5.前后台分离怎么测试?

    奇葩问题

    你们后端开发用的什么?

    移动端如何刷新页面?

    项目初始化构建流程

    项目中自己觉得骄傲的地方?

    说说自己的缺点

    热部署是什么?

    用户有多少

    怎么调用接口(是怎么跟后台沟通的)

    单元格测试是怎么做的

    开发环境,测试环境,上线环境的环境变量你们在开发中是如何处理的

    展开全文
  • 2021 前端面试题及答案

    万次阅读 多人点赞 2021-03-04 22:17:23
    2.React 项目用过什么脚手架(本是开放性题目) creat-react-app Yeoman 等 3什么时候用类组件Class Component,或函数组件Function 如果您的组件具有状态( state ) 或 生命周期方法,请使用 Class 组件。...
  • 2021前端面试题及答案

    万次阅读 多人点赞 2020-02-11 19:29:34
    前端面试汇总(2020年) 一 大纲 1、前言 2、前端工程化 3、前端设计模式 4、前端安全性问题 5、前端跨域问题 6、前端数据加密 7、前端http相关问题 8、*前端基础知识点面试题 9...
  • 分享一波今日做的前端面试真题里比较有价值的题目,希望大家能够共同进步 css篇 1.如何让字体变粗。 font-weight: bold; 2.解释 display: none;,visibility: hidden;,opacity: 0; 的异同。 display: none; 元素...
  • 翻资料组织了一下,非官方,仅供参考: 回答二:苟:您好,贵公司的面试题还挺有深度的,这让我越来越期待加入贵公司了。关于 ndoejs 是单线程的,刚好前段时间阅读过有关 node 的文章。node 的作者在设计之初选择...
  • 2021前端面试题以及答案解析

    千次阅读 2021-05-26 20:38:48
    1.v-show和v-if有什么区别 什么时候使用最好 区别:v-if是通过控制dom节点的存在与否来控制元素的显隐;v-show是通过设置DOM元素的display样式,block为显示,none为隐藏; 什么时候使用:如果需要非常频繁地切换...
  • 2021前端JavaScript面试题及答案

    千次阅读 多人点赞 2021-03-18 21:39:25
    准备面试的你,必看这8道JavaScript面试题,摸透JavaScript的基础 一、执行以下代码,测试浏览器会输出什么 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ...
  • 在这部分,我将详细讲解面试前我们需要做哪些方面的工作,以保证我们在面试过程中更加顺利。 准备一份漂亮的简历 一份漂亮的简历就是你进入大厂的敲门砖。 网上有很多教程教大家如何写出一份漂亮的简历,这里我就不...
  • 2021年最新web前端面试题及答案:CSS相关专题 说一下闭包 (1)什么是闭包: 闭包是指有权访问另外一个函数作用域中的变量的函数。 闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。闭包就是...
  • 2021高频前端面试题(含答案

    千次阅读 多人点赞 2021-04-22 13:54:18
    v-text/v-html/v-for/v-show/v-if/v-else/v-cloak/v-bind/v-on/v-model/v-slot… 四、综合 1、前端工程化理解(模块化、组件化、规范化、自动化) JS的模块化、css的模块化、资源的模块化 从UI拆分下来的每个包含...
  • 2021年最新前端面试题(字节跳动)真题解析,希望对你面试有帮助,加油。
  • 逻辑运算符 JavaScript中有三个逻辑运算符,&...HTML面试题部分 1.H5的新特性有哪些 2.Label的作用是什么?是怎么用的? 3.HTML5的form如何关闭自动完成功能 4.dom如何实现浏览器内多个标签页之间的通信? 5.实现不使
  • 2021最全面、最详细web前端面试题及答案总结

    万次阅读 多人点赞 2021-02-01 09:34:00
    2021最全面、最详细web前端面试题及答案总结 总结不易,希望可以帮助到即将面试或还在学习中的web前端小伙伴,祝面试顺利,拿高薪! 本章是HTML考点的⾮重难点,因此我们采⽤简略回答的⽅式进⾏撰写,所以不会有太...
  • 2021前端必问面试题及答案

    万次阅读 多人点赞 2020-09-17 19:53:47
    web前端面试题【持续更新】js基础1.原型链和继承2.浅拷贝和深拷贝3.闭包4.事件委托5.this指向,call/apply/bind,回调函数6.数组的常用操作7.promise8.set和weakset,map和weakmap9.let和const10.解构赋值11.typeof...
  • 近期总结一一些面试题 都是企业的面试题笔记题 感觉薪资10k下的都会出笔试题 特别高的薪资都是直接技术面试或者是 现场编程 总结很多人的面试题,后期会对于单个知识点再说笔记详细讲解。 部分都是百度的答案,...
  • 2021年腾讯、华为等前大厂前端面试题,非常适合校招、社招等想进大厂的开发人员
  • 2021Vue前端面试题总结(含答案

    千次阅读 2021-05-26 20:35:13
    面试官:JavaScript中什么是基本数据类型什么是引用数据类型?以及各个数据类型是如何存储的?⭐⭐⭐⭐⭐ 答: 基本数据类型有 Number String Boolean Null Undefined Symbol(ES6新增数据类型) bigInt ...
  • 2021前端面试及答案---(全部涉及比较全)

    千次阅读 多人点赞 2021-05-17 16:04:08
    2021前端面试及答案----(全部涉及) 更新中… 小编从四月十九号开始了面试之旅也是成功蹭到了五一带薪假,线下面试面了五家全过,(牛马?)过程中被问到的问题和面试前小编自己刷过 感觉重要的跟大家分享一下...
  • 答案与解析是我自己查询与思考后书写的,仅供参考。 北极光之夜。 auroras.blog.csdn.net 二.题目(答案在最后): 1.问一份标准的HTML文档有哪几个必须的HTML标签?【多选】 A. <html> B. <head> C...
  • 2021年最新(华为)前端面试题真题解析,希望对你有帮助,加油

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,994
精华内容 10,797
关键字:

前端面试题2021及答案