2022最新面试题JavaScript、Vue

JavaScript

typeof 和 instanceof的区别

  • typeof 会返回一个变量的基本类型,instanceof返回的是一个布尔值

  • instanceof 可以准确的判断复杂引用数据类型,但是不能正确判断基础数据类型

  • 而typeof 也存在弊端,它虽然可以判断基础数据类型(null除外),但是在引用数据类型中,除了Function类型以外,其他的也无法判断

  • 如果需要检测数据类型的话,可以通过Object.prototype.toString,调用该方法,统一返回格式“[object XXX]”字符串

  • Object.prototype.toString({})       // "[object Object]"
    Object.prototype.toString.call({})  // 同上结果,加上call也ok
    Object.prototype.toString.call(1)    // "[object Number]"
    Object.prototype.toString.call('1')  // "[object String]"
    Object.prototype.toString.call(true)  // "[object Boolean]"
    Object.prototype.toString.call(function(){})  // "[object Function]"
    Object.prototype.toString.call(null)   //"[object Null]"
    Object.prototype.toString.call(undefined) //"[object Undefined]"
    Object.prototype.toString.call(/123/g)    //"[object RegExp]"
    Object.prototype.toString.call(new Date()) //"[object Date]"
    Object.prototype.toString.call([])       //"[object Array]"
    Object.prototype.toString.call(document)  //"[object HTMLDocument]"
    Object.prototype.toString.call(window)   //"[object Window
    
    

javaScript 作用域

作用域即变量和函数生效的区域的集合,换句话说,作用域决定了代码区块中变量和其他资源的可见性。

我们一般讲作用域分为:全局作用域,函数作用域,块级作用域。

全局作用域

任何不在函数中或者大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问

函数作用域

函数作用域也叫局部作用域,如果一个变量是在函数内部声明的它就在一个函数作用域下。这些变量也只能在函数内部访问,不能在函数外访问

块级作用域

ES6引进了letconst关键字,和var关键字不同,在大括号中使用let和const声明的变量存在于块级作用域中。在大括号外不能访问这些变量。

词法作用域(看看即可)

词法作用域 又叫静态作用域,变量被创建好时就确定好了,而非执行阶段确定的。也就是说我们写好代码时它的作用域就确定了,JavaScript 遵循的就是词法作用域。

作用域链

当在JavaScript中使用一个变量的时候,首先JavaScript引擎会尝试在当前作用域下去寻找该变量,如果没找到,在到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域下

如果在全局作用域里仍然找不到该变量,它就会在全局范围内进行隐式声明该变量(非严格模式下)或是直接报错。

深拷贝和浅拷贝的区别

浅拷贝

浅拷贝指的是创建新的的数据,这个数据有着原始数据属性的一份精确拷贝。

如果属性是基础类型,拷贝的就是基础类型的值。如果属性是引用类型,拷贝的就是内存地址。

即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址。

//浅拷贝
function Clone(obj){
    const newObj = {};
    for(let prop in obj){
        newObj[prop] = obj[prop];
    }
    return newObj
}

深拷贝

深拷贝开辟一个新的栈,两个对象的属性完全相同,但是对应两个不同的地址,修改一个对象的属性时不会修改类外一个。

function deepClone(obj) {
    function isObject(obj) {
      return typeof obj === 'object' && typeof obj !== "null" 
    }
    if (!isObject(obj)) {
      throw new Error("输入参数不是对象")
    }
    let res = Array.isArray(obj) ? [...obj] : { ...obj };
    Object.keys(res).forEach((item) => {
      res[item] = isObject(res[item]) ? deepClone(res[item]) : res[item]
    })
    return res
  }

区别

浅拷贝和深拷贝都创建出一个新的对象,但是在复制对象属性时,浅拷贝只会复制属性指向某个对象的指针,而不是复制对象本身,新旧对象还是共享一块内存,修改对象属性会影响原对象,

而深拷贝会另外创建一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是新开劈一个栈空间

javaScript 原型

JavaScript每个对象都拥有一个原型对象,当去访问一个对象的属性时,它不仅仅在该对象上查找,还会搜寻对象的原型,以及该对象的原型的原型,依次层层向上搜寻,直到找到一个名字匹配的原型或者达到原型链的末尾

原型链

每个对象都可以有一个原型_proto_,这个原型还可以有它自己的原型,以此类推,形成一个原型链。查找特定属性的时候,我们先去这个对象里去找,如果没有的话就去它的原型对象里面去,如果还是没有的话再去向原型对象的原型对象里去寻找… 这个操作被委托在整个原型链上,这个就是我们说的原型链了。

闭包

一个函数和对其周围状态的引用捆绑在一起,这样的组合就叫闭包,也就是闭包让我们可以在一个内层函数中访问到其外层的作用域。

闭包的使用场景

任何闭包的使用场景都离不开两点

  • 创建私有变量
  • 延长变量的生命周期

this理解

this的定义

函数的this关键字在JavaScript中的变现略有不同,在绝大多数情况下,函数的调用方式决定了this的值。

this关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用他的对象。

this的指向

在全局函数中 this指向了window

在事件函数中 this指向了 事件对象

在对象的方法中 this指向了方法调用者

在构造函数中 this指向new 关键字创建的实例对象

在ES6的箭头函数中 this会在编译时绑定,首先箭头函数会从它的父级作用域下找,如果父级作用域还是箭头函数,在往上找,如此直到找到this的指向

JavaScript执行上下文

执行上下文是对JavaScript代码执行环境的一种抽象的概念,只要有JavaScript代码在运行,那么它就一定是运行在执行上下文中。

执行上下文的类型分为三种:

全局执行上下文:只有一个,浏览器中全局对象就是window对象,this指向了这个全局对象。

函数执行上下文:存在无数个,只有在函数被调用时候才会被创建,每次调用函数都会创建一个新的执行上下文。

Eavl 函数执行上下文:值得是运行在Eavl函数中的代码,很少且不建议使用。

函数的防抖和节流

本质上是优化高频率执行代码的一种手段

他们的定义是:

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

节流代码实现:

function thorttled(fn,delay = 500){
    let timer = null;
    let starttime = Date.now();
    return function(){
        let curTime = Date.now()//当前时间
        let remaining = delay - (curTime - startime) //从上一次到现在,还剩下多少多余时间
       //这时后this的指向是事件对象
        let context = this
        //args里面装的是事件对象的参数 事件对象e
        let args = arguments;
        //触发事件时 先清除一次定时器
        clerTimeout(timer)
        //判断事件是否该执行了
        if(remainig <= 0){
            //调用apply立即执行 (不传参也可以实现)
            fn.apply(context,args)
            //重置事件
            starttime= Date.now()
        }else{
            //如果不用立即执行 那么等待剩余的时间在执行
            timer = setTimeout(fn,remaining)
        }
    }
}

防抖 :

function Shake(fn,delay = 500){
    let timer = null;
    return function(...args){
        //判断延时器是否开启了
        if(!timer){
            timer = setTimeout(()=>{
              //如果第一次进来 调用传进来的fn函数
                fn.apply(this,args)
                //清空定时器
                tiemr = null
            // 延时时间 
            },delay)
        }
    }
}

new 操作符具体干了什么

  1. 当使用new操作符时会创建一个新对象
  2. 为这个空对象内部添加__proto__属性,并将该属性链接至构造函数内部的prototype原型上
  3. 构造函数调用call方法,并将该对象设置为参数,构造函数的this指向修改成这个空对象
  4. 返回这个空对象

JavaScript继承

继承的概念:

继承是面向对象软件技术当中的一个概念。

继承可以使子类具有父类的各种属性和方法,而不需要再次编写同样的代码,在子类继承父类别的同时,可以重新定义某些属性和方法,使其获得与父类不同的功能。

继承的实现方式:

JavaScript常见的继承方式:

  • 原型链继承(1)
  • 构造函数继承(借助call) (1)
  • 组合继承(1)
  • 原型式继承 (0)
  • 寄生式继承(0)
  • 寄生组合继承(0)
  1. 原型链继承:

原型链继承: 两个实例使用的是一个原型对象,内存空间是共享的。

  1. 构造函数继承:

构造函数继承存在着 :父类原型对象中一旦存在父类之前自己定义的方法,那么子类将无法继承这些方法。

  1. 组合继承:

组合继承则是将原型继承 和构造函数继承组合起来。

事件代理

​ 事件代理 就是把一个元素响应事件的函数委托到另一个元素。事件代理,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素。当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件,然后在外层元素上去执行函数。

事件流的三个阶段

事件流都会经历三个阶段 捕获阶段——目标阶段——冒泡阶段

事件循环

理解:

javascript从诞生之日起就是一门 单线程的 非阻塞的 脚本语言,单线程意味着,javascript代码在执行的任何时候,都只有一个主线程来处理所有的任务,非阻塞靠的就是 event loop(事件循环)

event loop它最主要是分三部分:主线程、宏队列(macrotask)、微队列(microtask)

js的任务队列分为同步任务和异步任务,所有的同步任务都是在主线程里执行的,异步任务可能会在macrotask或者microtask里面

宏队列(macrotask)

setTimeout、setInterval、setImmediate、I/O、UI rendering

微队列(microtask)

promise.then、process.nextTick

执行顺序

1、先执行主线程

2、遇到宏队列(macrotask)放到宏队列(macrotask)

3、遇到微队列(microtask)放到微队列(microtask)

4、主线程执行完毕

5、执行微队列(microtask),微队列(microtask)执行完毕

6、执行一次宏队列(macrotask)中的一个任务,执行完毕

7、执行微队列(microtask),执行完毕

8、依次循环。。。

概念:

事件循环 :在JavaScript中所有任务可以分为同步任务,和异步任务,同步任务进入主线程,宏任务和微任务进入任务队列,主线程的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行,这就是事件循环

宏任务和微任务

微任务:

一个需要异步执行的代码的函数,执行时机是在主函数执行结束之后,当前宏任务结束之前:

常见的微任务:

Promise

proxy

宏任务:

宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的

常见宏任务:

script

setTimeout/setInterval

执行机制:

执行一个宏任务,如果遇到微任务就将它放到微任务的时间队列中。

当前宏任务执行完毕后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完

谈谈你对promise的理解

Promise 是ES6新增的语法 是异步编程的一个解决方案,将异步操作以同步的操作流程表达出来,避免以前使用回调函数带来的回调地狱的问题,

Promise 是一个构造函数,我们可以通过该构造函数来生成Promise的实例。

Promise有三个状态:pending (等待) fulfilled(成功)rejected(失败)

Promise常用的方法有: .then() .catch .all .race

ES6

var ,const ,let之间的区别

1. var

在ES5中,顶层对象和全局变量是等价的,用var声明的变量即是全局变量,也是顶层变量;

(顶层对象:在浏览器环境下指的是window,在node指的是globar对象)

使用var声明的变量存在变量提升的情况。

var 可以对一个变量进行多次声明,后面的变量会覆盖掉前面的变量。

2.let

let 是__ES6__新增的命令,用来声明变量。

用法类似于var,但是let所声明的变量,只在let命令所在的代码块内有效。

let 不存在变量提升,只要块级作用域内存在let 命令,这个区域就不再受外部影响,

使用let声明变量前,该变量都不可用,也就是我们说的暂时性死区。

let 不允许相同作用域下的重复声明。

3.const

const 声明一个只读的常量,一旦声明常量的值就不可改变,也就是说const一旦声明,就必须立即初始化。

如果之前使用过var 或 let 声明过变量,就不能在用const声明。

const 实际上并不是变量的值不能改动,而是变量所指向的内存地址不得改动。

对于简单数据的数据,值就保存在变量指向的地址,因此等同于常量。

对于复杂数据类型来说,变量指向的内存地址,保存的只是一个指向实际数据的指针,cosnt可以保证这个指针是固定的,并不能确保该变量的结构不变。其他情况const与let一致。

区别:

var 不存在暂时性死区。let, const存在暂时性死区。

var不存在块级作用域,let,const存在块级作用域。

var 可以重复声明,let,const在同一作用域下不允许重复声明。

var 和let 可以修改声明的变量,const 声明一个只读的常量,一旦声明,常量的值就不可改变。

扩展运算符(…)

ES6新增了扩展运算符… 可以将一个数组转为用逗号分隔参数序列。

它可以将某些数据结构转换为数组 比如伪数组

可以用于数组间的合并

能够实现简单的数组复刻,但是扩展运算符实现的是浅拷贝,修改了引用指向的值,会同步反应给新数组。

ES6中新增的Set ,Map两种数据结构怎么理解

Set是一种叫做集合的数据结构,Map是一种叫做字典的数据结构。

集合:就是由一堆无序的,相关联的,且不重复的内存结构组成的组合。

字典 :是一些元素的集合。每个元素都有一个称作key的域,不同元素的key各不相同。

区别:

  • 共同点:集合,字典都可以储存不重复的值。
  • 不同点:集合是以[值,值] 的形式储存元素,字典是以[键,值]的形式储存。

VUE的单向数据流

Vue 的单向数据流:指数据一般从父组件传到子组件,子组件没有权利直接修改父组件传来的数据,即子组件从 props 中直接获取的数据,只能请求父组件修改数据再传给子组件。父级属性值的更新会下行流动到子组件中。

vuewatch和computed的区别

computed

computed适合处理的场景是,一个数据属性在它所依赖的属性发生变化时,也要发生变化,这种情况下,我们最好使用计算属性,computed是带缓存的,只有其引用的响应式属性发生改变时才会重新计算

不支持异步,当computed内有异步操作时无效,无法监听数据的变化

watch

watch更多得是观察的作用,无缓存性,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。

运用场景:

计算属性: 当我们需要进行数值计算,并且依赖于其他数据时,应该使用computed,因为可以利用computed的缓存特性,避免每次获取值时,都要重新计算。

侦听器: 当我们需要在数据变化时执行异步或者开销较大的操作时,应该使用watch,因为watch选项允许我们执行异步操作,限制我们执行该操作的频率,并在我们得到最终结果前,设置中间件状态。这些都是计算属性无法做到的。

多个因素响应一个显示使用computed ;一个元素变化响应多个其他因素 显示 使用watch

computed 和methods的区别

methods使用时,一般情况需要加括号,而computed则不需要。

methods每次调用时会重新执行函数,而computed在其内部变量不变或其返回值不变的情况下多次调用只会执行一次,后续执行时直接从缓存中获取该computed的结果。

直接给一个数组项赋值,Vue 能检测到变化吗?

由于 JavaScript 的限制,当你利用索引直接设置一个数组或当你修改数组的长度时 Vue检测不到。

vue导航守卫

  1. 全局前置守卫:router.beforeEach

  2. 全局解析守卫:router.beforeRsolve

  3. 全局后置钩子:router.afterEach 后置钩子没有next参数也不会改变导航本身

  4. 路由独享守卫:beforeEnter 路由独享守卫 可以直接路由配置上定义,路由独享守卫只在进入路由时触发。

  5. 组件内的守卫:beforeRouteEnter 在渲染该组件的对应路由被验证前触发,不能获取实例this,因为守卫执行时,组件实例还未被创建。

    beforeRouteUptate:在当前路由改变,组件被复用时调用。可以访问this,因为组件实例已经挂载完毕。

    beforeRouteLeave:在导航离开渲染该组件的对应路由时调用

git常用命令

新增文件的命令:git add file或者git add .
提交文件的命令:git commit –m或者git commit –a
查看工作区状况:git status –s
拉取合并远程分支的操作:git fetch/git merge或者git pull
查看提交记录命令:git reflog

谈谈你对前端性能优化的理解

a. 请求数量:合并脚本和样式表,CSS Sprites,拆分初始化负载,划分主域

b. 请求带宽:开启GZip,精简JavaScript,移除重复脚本,图像优化,将icon做成字体

c. 缓存利用:使用CDN,使用外部JavaScript和CSS,添加Expires头,减少DNS查找,配置ETag,使AjaX可缓存

d. 页面结构:将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出

e. 代码校验:避免CSS表达式,避免重定向

对BFC规范的理解

BFC全称是Block Formatting Context,即块格式化上下文。它是CSS2.1规范定义的,关于CSS渲染定位的一个概念。

BFC是页面CSS 视觉渲染的一部分,用于决定块盒子的布局及浮动相互影响范围的一个区域。

BFC的一个最重要的效果是,让处于BFC内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。

利用BFC可以闭合浮动,防止与浮动元素重叠。

请说出三种减少页面加载时间的方法

a. 尽量减少页面中重复的HTTP请求数量

b. 服务器开启gzip压缩

减少dom元素数量

避免重定向

使用cdn

c. css样式的定义放置在文件头部

d. Javascript脚本放在文件末尾

e. 压缩合并Javascript、CSS代码

f. 使用多域名负载网页内的多个文件、图片

性能优化

1.什么是预加载

资源预加载是一个性能优化技术,我们可以使用该技术来预先告知浏览器某些资源可能在将来会被使用到。预加载简单来说就是将所有所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源

   //myPreload.js文件
    var image= new Image()
    image.src="http://pic26.nipic.com/20121213/6168183 004444903000 2.jpg"

1.什么是懒加载?

懒加载也就是延迟加载。
当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次,俗称占位图),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。这就是图片懒加载。

3.懒加载的原理是什么?

页面中的img元素,如果没有src属性,浏览器就不会发出请求去下载图片,只有通过javascript设置了图片路径,浏览器才会发送请求。
懒加载的原理就是先在页面中把所有的图片统一使用一张占位图进行占位,把正真的路径存在元素的“data-url”(这个名字起个自己认识好记的就行)属性里,要用的时候就取出来,再设置;

2)区别:
两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

组件的传值

一、父组件向子组件传递数据

在 Vue 中,可以使用 props 向子组件传递数据。

二、子组件向父组件传递数据

子组件主要通过事件传递数据给父组件

三、非父子组件传递数据

非父子组件间传值有两种方法,一种是vuex共享数据,

另一种是Bus

vuex的长期储存

因为Vuex里的数据是保存在内存中的,这就面临一个问题:页面一刷新,内存就清空,导致当前页面恢复到原来的样子。

那么怎么让数据长久的保存呢?我们可以把数据保存在localstorage中,

圣杯布局

【1】flex弹性盒子

  • header和footer设置样式,横向撑满。
  • container中的left、center、right依次排布即可
  • 给container设置弹性布局 display: flex;
  • left和right区域定宽,center设置 flex: 1; 即可

data为什么是一个函数

组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。

methods中可以写箭头函数吗

vue中的methods不可以使用箭头函数,因为this指向的不是vue实例,使用箭头函数打印this,发现是undefined

vue上传图片

1.云储存

常见的 七牛云,OSS(阿里云)等,这些云平台提供API接口,调用相应的接口,文件上传后会返回图片存储在服务器上的路径,前端获得这个路径保存下来提交给后端即可。此流程处理相对简单。

主要步骤

向后端发送请求,获取OSS配置数据
文件上传,调用OSS提供接口
文件上传完成,后的文件存储在服务器上的路径
将返回的路径存值到表单对象中

Vue.nextTick():

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

MVVM 基本定义

1.MVVM 即 Model-View-ViewModel 的简写。即模型-视图-视图模型。

2.模型(Model) 指的是后端传递的数据。

3.视图(View)指的是所看到的页面。

4.视图模型(ViewModel)是 mvvm 模式的核心,它是连接 view 和 model 的桥梁。它有两个方向:

一是将模型(Model)转化成视图 (View),即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。

二是将视图 (View)转化成模型(Model),即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件 监听。这两个方向都实现的,我们称之为数据的双向绑定。

什么是diff算法?

diff算法就是用JavaScript来表示一个dom树的结构
然后用这个dom去构建一个真实的dom 插入到文档中
当状态变更的时候 重新构造一个dom树 比较新旧dom树 记录两个dom树的差异 并且通知视图开始更新

diff算法就 用来比较vdom结构的

什么是虚拟dom?

它是一个object对象模型 用来模拟真实的dom
作用是高效的渲染页面 减少不必要的dom操作 提高渲染效率

你做过最大的项目是什么

说一个b端项目 就可以

你碰到的技术难点

当我们使用路由渲染列表时,页面中去调用menu菜单来进行页面渲染出现了问题 ,在menu菜单中我们使用的是import导入组件 设置路由菜单的component 属性,然后在页面引用该菜单时,父级路由的component变成了 undefined ,在想了很多种办法后,多次尝试,把import引入改成懒加载引入即可解决。原理可能是因为 menu中引入了 layout组件 ,layout组建中又引入了menu菜单而导致的。

内存泄漏

程序中已动态分配的堆内存由于某种原因程序未释放或者无法释放引发的各种问题。

会运行变慢,崩溃,延迟大等。

  • BOM / DOM对象泄漏
  • scipt中存在对BOM / DOM对象的引用
  • javaScript对象泄漏
  • 定时器未清除
  • 闭包函数导致的泄漏

js的垃圾回收机制

js的垃圾回收机制就是为了防止内存泄露的,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉他们所指向的内存。

回流和重绘

  • 回流:当一个元素自身的宽高,布局,显示或隐藏,或元素内部的文字结构发生变化,导致需要重新构建页面的时候,就产生了回流
  • 重绘:当一个元素自身的宽高,布局,及显示或隐藏没有改变,而只是改变了元素的外观风格的时候,就产生了重绘

回流触发时机

  • 添加或删除可见的DOM元素
  • 元素的位置发生变化
  • 元素的尺寸发生变化
  • 内容发生变化
  • 页面一开始渲染的时候
  • 浏览器的窗口尺寸变化

重绘触发时机

  • 颜色的修改
  • 文本方向的修改
  • 阴影的修改

如何进行性能优化?

用transform 代替 top,left ,margin-top, margin-left… 这些位移属性

不要使用 js 代码对dom 元素设置多条样式,选择用一个 className 代替之

不要在循环内获取dom 的样式例如:offsetWidth, offsetHeight, clientWidth, clientHeight等。浏览器有一个回流的缓冲机制,获取这些属性时会产生回流

避免设置多层内联样式,写个外部类这样只回流一次

让多次回流的元素脱离文档流比如动画,使用 position 属性的 fixed 值或 absolute 值

一起变化(同时修改所有需要变化的属性)

区别:

他们的区别很大:
回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流
当页面布局和几何属性改变时就需要回流

attribute和property的区别

attribute和是dom元素在文档中作为html标签拥有的属性

propetry是dom元素在js作为对象拥有的属性

对于html的标准属性来说,attribute和property是同步的,是会自动更新的。

但是对于自定义属性来说,他们是不同步的。

数组的方法

map:遍历数组,返回回调返回值组成的新数组。

forEach:遍历数组,无法break,可以用抛出错误来停止

filter:过滤数组

some:遍历数组,有一项返回true,则整体为true

every:有一项返回false,则整体都是false

join:通过指定连接符生成字符串

sort:数组排序

push:末尾添加元素

reverse:反转数组

面向对象编程思想

面向对象的就是使用对象,类,继承,封装等基本概念进行程序设计,

它易维护,易扩展,开发工作的重用性,继承性高,降低重复工作量。

缩短了开发周期。

负载均衡

单台服务器共同协作,不让其中莫一台或者几台超额工作,发挥服务器的最大作用。

http重定向负载均衡:调度者根据策略选择服务器以302响应请求,缺点只有第一次有效果,后续操作维持在该服务器的dns负载均衡:解析域名时,访问多个ip服务器中的一个 。 避免dom渲染的冲突

反向代理负载均衡:访问统一的服务器,由服务器进行调度访问实际的某个服务器,对统一的服务器要求大,性能收到服务器群的数量

NG部署

Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。

基本操作指令:

启动服务:start nginx

完整有序停止:nginx -s quit

强制关闭:nginx -s stop

重载服务:nginx -s reload  (修改配置文件之后,需要重启加载,服务不会中止)

验证配置文件:nginx -t

打开日志文件:nginx -s reopen

使用帮助:nginx -h

vue-loader是什么?它的用途是什么

vue文件的一个加载器,将template/js/style转换为js模块

用途:js可以写es6,style样式

什么是vue的生命周期?有什么作用

每个Vue 实例被创建时都要经过一系列的初始化过程,例如需要设置数据监听、编译模板、将实例挂载到DOM并在数据变化时更新DOM等,同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己代码的机会。

第一次页面加载会触发哪些钩子

beforeCreate created beforeMount mounted

VUE获取数据一般在哪个周期函数中

created beforeMount mounted

自定义指令是什么

指令本质上是装饰器,是vue对html元素的扩展,给html元素添加自定义功能。vue编译dom时,会找到指令对象,执行指令相关方法。

自定义指令有五个声明周期

  1. bind 只调用一次 指令第一次绑定到元素时调用
  2. inserted:被绑定元素插入父节点是调用
  3. update :被绑定元素所在模块更新时调用,而不论绑定至是否变化。通过比较前后的值。
  4. componentUpdated:被绑定元素所在模板完成一次更周期时调用
  5. unbind :只调用一次,指令和元素解绑时调用

生命周期钩子是如何实现的

Vue的声明周期钩子核心实现是利用发布订阅模式先把用户传入的生命周期钩子订阅好(内部采用数组的方法存储)然后在创建组件实例的过程中会一次执行对应的钩子方法;

MVC

MVC全名是 Model View Controller,即模型-视图-控制器,一种软件设计典范

模型:指的是后端传递的数据。

视图:视图(View)指的是所看到的页面。

控制器:是应用程序处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并像模型发送数据。

项目部分

你项目中的网络/api请求模块是怎么封装的?

  1. 接口一般都是异步的,可以返回promise更加清晰
  2. 网络请求url的公共部分可以单独配置到网络请求内部
  3. 针对所有接口可以进行统一的处理,这也是面向切面编程的一个实践
  4. 一般借助第三方库 axios 快速的封装网络请求模块

你们的项目开发流程/项目流程是什么样子的?

首先产品写需求文档 对需求评估 如果需求复杂的话就要写一个技术文档 沟通一下

项目规划 PM会对任务进行分配一下

然后就是ui画图 ue设计

然后我们前段 对着原型图开发 开发前跟后端联调跟他们讲要什么接口 接口什么样子的要么就后端给一个接口文档

测试 我们前端跟测 没问题就上线 上线前给产品看一下 产品觉得没问题就上线

  1. 产品出需求;开需求会;
  2. 估时,部分项目写技术方案;接口阅读
  3. 开始开发;测试给冒烟测试/测试用例评审
  4. 前后端联调
  5. 冒烟测试
  6. 提测
  7. 跟测/上环境
  8. 项目上线/项目跟踪/项目总结

SPA单页面

SPA 仅在Web页面初始化时加载对应的HTML,JavaScript,和Css

一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转

而页面的变化时利用路由机制实现HTML内容的变换,避免页面的重新加载

优点:用户体验好,内容改变使用的是局部刷新,避免了不必要的跳转和重复渲染

减轻了服务器的压力,前后端职责分离,架构清晰。

缺点:初次加载耗时多,不利于搜索引擎检索,在SEO上有天然的弱势。

Vue数据双向绑定原理

实现mvvm的数据双向绑定,是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来给各个属性添加setter,getter并劫持监听,在数据变动时发布消息给订阅者,触发相应的监听回调。就必须要实现以下几点:
1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图

用index作为key可能会引发的问题

  • 若对数据进行:逆序添加/逆序删除等破坏顺序的操作,会产生没有必要的真实DOM更新,界面效果虽然没有问题,但是数据过多的话,会效率过低;
    • 如果结构中还包含输入类的DOM,会产生错误DOM更新,界面有问题;
      • 注意!如果不存在对数据的逆序操作,仅用于渲染表用于展示,使用index作为key是没有问题的。

为什么使用proxy API代替 defineProperty API

  1. defineProperty的局限性的最大原因是因为它只能针对单例属性进行监听。vue2中对data属性做了遍历+递归,为每个属性设置getter,setter。这也就是为什么vue只能对data中预定义的属性做出响应的原因
  2. 在vue中使用下标的方式直接修改属性的值或者添加一个预先不存在的对象属性是无法做到setter监听的,这是defineProprty的局限性
  3. Proxy的监听是针对一个对象的,那么对这个对象的所有操作会进入监听操作,这样就完全可以代理所有属性,将会带来很大的性能提升和更优的代码
  4. Proxy可以理解成,在目标对象之前架设一层拦截,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

Vue 的异步更新机制是如何实现的?

Vue 的异步更新机制的核心是利用了浏览器的异步任务队列来实现的,首选微任务队列,宏任务队列次之。

大小端存储讲一下

大小端存储的理解有两点

1 是针对字节而言. 从字节高位到低位是大端,反之是小端. 一个字节里面的八位不会改变顺序

2 大端小端指的是内存中字节存储的顺序.

cookie的作用域

cookie对象的domain属性设置了cookie的作用域。domain本身以及domain的子域名可以访问到相关cookie。

cookie跨域

允许cookie跨域"Access-Control-Allow-Credentials", “true” 前端设置 withCredentials: true 前端代码

http2.0get请求和post请求的区别,两者本质是一样的

get:请求URL标志的文档 获取信息而非修改信息,get请求一般不产生副作用

post向服务器发送数据

get传送的数据量较小,不能大于2KB;post传送的数据较大,默认不受限制,但实际为80/100KB

GET产生一个TCP数据包;POST产生两个TCP数据包。

强缓存和协商缓存

强缓存

服务器通过设置http中的header的Expires和cach-control字段告诉浏览器缓存的有效期

协商缓存

简单地说,协商缓存就是通过服务器来判断缓存是否可用。

js基本数据类型,null和undefined区别

null

在 JavaScript 中 null 表示 “什么都没有”。

undefined

在 JavaScript 中, undefined 是一个没有设置值的变量。

null 和 undefined 的值相等,但类型不等:

es6的模块化和commen

ES6 模块与 CommonJS 模块存在以下差异:

1、CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用

  • CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
  • ES6 Modules 的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6的import 有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

2、CommonJS 模块是运行时加载,ES6 模块是编译时输出接口

  • 运行时加载: CommonJS 模块就是对象;即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。
  • 编译时加载: ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,import时采用静态命令的形式。即在import时可以指定加载某个输出值,而不是加载整个模块,这种加载称为“编译时加载”

发布者订阅者模式

发布者订阅者模式其实就是一种对象间一对多的依赖关系(利用消息队列),

当一个对象的状态发生改变时,所有依赖于他的对象都会得到状态改变的通知,

订阅者把自己想订阅的事件注册到调度中心,当发布者发布该事件时到调度中心,也就是事件触发时,由调度中心统一调度订阅者注册到调度中心的代码

观察者模式

定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

区别

虽然两种模式都存在订阅者和发布者(具体观察者可认为是订阅者、具体目标可认为是发布者) 都相同,但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会。

两种模式都可以用于松散耦合,改进代码管理和潜在的复用。

事件冒泡

事件冒泡是由IE开发团队提出来的,即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播。

事件捕获

事件捕获是先由最上一级的节点先接收事件,然后向下传播到具体的节点。

Symbol

(ES6 新增数据类型)

Symbol 本质上是一种唯一标识符,可用作对象的唯一属性名,这样其他人就不会改写或覆盖你设置的属性值

Symbol 数据类型的特点是唯一性,即使是用同一个变量生成的值也不相等。

Symbol 数据类型的另一特点是隐藏性,for···in,object.keys() 不能访问

但是也有能够访问的方法:Object.getOwnPropertySymbols

BigInt

(ES6 新增数据类型)

BigInt 是一种特殊的数字类型,它提供了对任意长度整数的支持。
创建 bigint 的方式有两种:在一个整数字面量后面加 n 或者调用 BigInt 函数。

纯函数

  1. 输入输出数据流全是显式(Explicit)的。 显式(Explicit)的意思是,函数与外界交换数据只有一个唯一渠道——参数和返回值。函数从函数外部接受的所有输入信息都通过参数传递到该函数内部。函数输出到函数外部的所有信息都通过返回值传递到该函数外部。

函数的副作用

函数副作用 指当调用函数时,除了返回函数值之外,还对主调用函数产生附加的影响。例如修改全局变量(函数外的变量)或修改参数。

函数副作用会给程序设计带来不必要的麻烦,给程序带来十分难以查找的错误,并且降低程序的可读性。严格的函数式语言要求函数必须无副作用。

非纯函数 ( Impure Function )

与之相反。 隐式(Implicit)的意思是,函数通过参数和返回值以外的渠道,和外界进行数据交换。比如读取/修改全局变量,都叫作以隐式的方式和外界进行数据交换。

引用透明 ( Referential Transparent )

引用透明的概念与函数的副作用相关,且受其影响。 如果程序中两个相同值得表达式能在该程序的任何地方互相替换,而不影响程序的动作,那么该程序就具有引用透明性。它的优点是比非引用透明的语言的语义更容易理解,不那么晦涩。纯函数式语言没有变量,所以它们都具有引用透明性。

从 URL 输入到页面展现到底发生什么?

浏览器通过向 DNS 服务器发送域名,DNS 服务器查询到与域名相对应的 IP 地址,然后返回给浏览器,浏览器再将 IP 地址打在协议上,同时请求参数也会在协议搭载,然后一并发送给对应的服务器。

post请求几种常见content-type类型

application/x-www-form-urlencoded

这应该是最常见的 POST 提交数据的方式了。浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。

multipart/form-data

使用表单上传文件时,必须让 form 的 enctyped 等于这个值。

application/json

这种类型是我们推荐的,。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。

你可能感兴趣的:(前端,javascript,vue.js,前端)