前端总结

闭包以及应用场景


  • 作用域
    • 作用域决定了代码区块中变量、函数、对象和其他资源的可见性
    • 全局作用域、函数作用域和块级作用域
      • letconst 声明的变量不会提升到代码块顶部。
      • 在同一作用域内,禁止重复声明
      • for 循环中,设置循环变量那部分是一个父作用域,而循环体内部是一个单独的子作用域。由于var不能定义块级作用域,在循环体或者循环内部,使用 var 定义变量,在循环外部可以访问到变量
  • 作用域链
    • 父级作用域是在定义的时候就确定的,不是执行时确定
    • 当前作用域不存在的变量称为自由变量,会沿着作用域链寻找
  • 闭包概念
    • JavaScript 语言特有的 "链式作用域" 结构,子对象会一级一级地向上寻找所有父对象的变量。所以父对象的所有变量,对子对象都是可见的,反之则不成立。
    • 闭包就是能够读取其他函数内部变量的函数,就是将函数内部和函数外部连接起来的一座桥梁
  • 用途:
    • 外部函数读取函数内部的变量
    • 让变量的值始终保存在内存中
  • 注意点:
    • 由于使用闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题。解决方法是在退出函数之前,将不使用的局部变量全部删除
    • 闭包会在父函数外部,改变父函数内部变量的值。不要随便使用父函数对象调用属性的方式改变内部变量的值。

面试题目:

Excuse me?这个前端面试在搞事!

function a() {
  for (var i = 0; i < 8; i++) {
    setTimeout(function() {
      console.log(i, 1000 * i)
    },
    1000 * i)
  }
}
// 结果:每隔一秒打印 8,8000,共打印8次
function b() {
  for (var i = 0; i < 8; i++) { (function() {
      setTimeout(function() {
        console.log(i, 1000 * i)
      },
      1000 * i)
    })();
  }
}
// 结果:每隔一秒打印 8,8000,共打印8次
function c() {
  for (var i = 0; i < 8; i++) {
    setTimeout((function(i) {
      console.log(i, 1000 * i)
    })(i), 1000 * i)
  }
}
// 结果:没有延迟,一次打印全部。自执行函数,传入变量参数。闭包。
> 0, 0
> 1, 1000
> 2, 2000
> 3, 3000
> 4, 4000
> 5, 5000
> 6, 6000
> 7, 7000
function d(){
    for (let i = 0; i < 8; i++) {
    setTimeout(function() {
      console.log(i, 1000 * i)
    },
    1000 * i)
  }
}
// 结果:每隔一秒,打印一次结果。使用块级作用域。闭包。
> 0, 0
> 1, 1000
> 2, 2000
> 3, 3000
> 4, 4000
> 5, 5000
> 6, 6000
> 7, 7000
function f() {
  for (var i = 0; i < 8; i++) { 
    (function(i) {
      setTimeout(function() {
        console.log(i, 1000 * i);
      },
      i * 1000);
    })(i);
  }
} 
// 结果:每隔一秒,打印一次结果。闭包。
> 0, 0
> 1, 1000
> 2, 2000
> 3, 3000
> 4, 4000
> 5, 5000
> 6, 6000
> 7, 7000
function test() {
  for (var i = 0; i < 8; i++) {
   (function() {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
  })(i);
 }
}
// 结果:每个一秒,打印一次结果。结果都是8,8000

this的指向


  • this 要在执行时才能确认值,定义时无法确认
  • 箭头函数this指向: 箭头函数没有自己的this,看其外层是否有函数
    • 如果有,外层函数的this就是内部箭头函数的this
    • 如果没有,则this就是window
      前端总结_第1张图片
      this指向

面试题目

this指向和闭包结合的问题

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
  console.log(object.getNameFunc()());
// 结果: The Window
  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
  console.log(object.getNameFunc()());
// 结果:My Object

Vue中的什么情况下this指向Vue实例


  • 所有的生命周期钩子自动绑定 this 上下文到实例中,因此你可以访问数据,对属性和方法进行运算。

判断浏览器和系统的信息


使用 navigator 对象

输入网址到加载完页面的过程


  • 加载一个资源的过程
    • 浏览器根据 DNS 服务器取得域名的 IP 地址
    • 向这个 IP 的机器发送http 请求
    • 服务器收到、处理并返回 http 请求
    • 浏览器得到返回内容
  • 浏览器渲染页面的过程
    • 根据 HTML 机构生成 DOM Tree;根据 CSS 生成 CSSOM
    • DOMCSSOM 整合形成 RenderTree,根据 RenderTree 开始渲染和展示
    • 遇到 script 时,会执行并阻塞渲染

Vue的渲染过程


  • new Vue,执行初始化
  • 挂载 $mount 方法,通过自定义 Render 方法、template模板、el 等生成 Render 函数
  • Vue会遍历传入实例的data选项,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把 "接触" 过的数据属性记录为依赖。通过 Watcher 监听数据变化。响应式开始监听。
  • 当依赖项的 setter 触发时,会通知watcherRender 函数执行,生成 VNode 对象
  • 通过 patch 方法,对比新旧 VNode 对象,通过 DOM Diff 算法,添加、删除、修改真正的 DOM 元素

Cookie、Session、LocalStorage、SessionStorage的区别


  • cookiesession 都是用来跟踪浏览器用户身份的会话方式。cookie存储在浏览器端,session 存储在服务器端
  • 功能:cookie 本身用于客户端和服务器端通信,它有本地存储的功能,于是也被当做存储使用。LocalStorageHTML5 中专门为存储设计
  • 容量:cookie 存储量太小,最大容量 4kB; LocalStorage 最大容量为 5M
  • HTTP请求:所有的http请求,都会携带cookie ,会影响获取资源的效率

同源策略和跨域解决方案


  • 同源策略:
    • 目的是为了保证用户信息的安全,防止恶意的网站窃取数据。
    • "同源" 指的是"三个相同":协议相同、域名相同、端口相同。
    • 非同源,浏览器端会限制三种行为:
      • CookieLocalStorageIndexDB 无法读取
      • DOM 无法获得
      • Ajax 请求不能发送
  • 跨域:协议、域名、端口,有一个不同就算跨域
  • 解决方案:
    • JSONP
      • 利用 script 标签没有跨域限制的漏洞,动态插入 script 标签,实现跨域获取数据,JSONP 请求一定需要对方的服务器做支持才可以
      • JSONP 仅支持 get 方法,具有局限性。不安全,可能会遭受 XSS 攻击
    • CORS 跨域方式,服务器端设置HTTP消息头。需要浏览器和服务器同时支持, IE 浏览器不能低于 IE10。整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。浏览器一旦发现 Ajax 请求跨源,就会自动添加一下附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
    • nginx 反向代理实现跨域;node 请求转发实现跨域

正则表达式


  • 普通文本字符
  • 元字符
    • 匹配一个字符:匹配行的起始 ^;匹配行的结束 $;匹配任意一个字符 .;匹配若干字符之一的字符组 [...];匹配一个未列出的字符的排除型字符组 [^...]
    • 多选结构:每个多选结构自身都可以是完整的正则表达式,都可以匹配任意长度的文本;匹配任意子表达式 || 配合 ()可以限制子表达式的界限
    • 量词:作用与之前紧邻的元素,包括单个元素或使用 () 限制起来 的元素
      • ? :0次或者1次
      • +:1次或者多次
      • *:任意多次或者0次
      • {a, b}[a, b]
    • 转义: \,匹配的某个字符就是元字符,则需要进行转义

px、em、rem


  • px 像素是相对长度单位,相对于显示器屏幕分辨率而言
  • em 是相对长度单位,相对于当前对象内文本的字体尺寸。如果当前未对文本的字体尺寸进行设置,则相对于浏览器的默认字体尺寸
  • remroot emCSS3 中新增的一个相对单位。相对的是HTML根元素

CSS3新增的特性


  • 选择器:伪类选择器 :first-child:last-child:nth-child(n)
  • 动画效果:TransitionsTransformsAnimation
  • 边框:圆角边框、边框阴影、边框图片
  • 颜色:RGBA、渐变颜色
  • 文本:文本溢出、文本阴影

Vue项目部署


使用webpack构建工具,npm script脚本将项目打包成资源文件,部署到 nginx 服务器上

MVVM


VueMVVM 架构,ViewModelModelView 之间的一个桥,相当于一个连接器,内部实现事件监听和双向数据绑定

Vue的生命周期


所有的声明周期钩子自动绑定 this 上下文到实例中,因此你可以访问数据,对属性和方法进行运算

  • beforeCreate:在实例初始化之后,数据观测(data observer)和event/watcher事件配置之前被调用
  • created:在实例创建完成后被立即调用。已完成:数据观测、属性和方法的运算、watch/event事件回调。挂载阶段还没开始,$el属性目前尚不可用
  • beforeMount:在挂载开始之前被调用:相关的reader函数首次被调用
  • mounted:实例被挂载后调用,这时的el 被新创建的 vm.$el替换了。mounted不会保证所有的子组件也都一起被挂载。确保整个视图都渲染完毕,可以在mounted内部使用vm.$nextTick
  • beforeUpdate:数据更新时调用,发生在虚拟DOM打补丁之前。
  • updated:由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。updated 不会保证所有的子组件也都一起被重绘。相关操作放在updated钩子中调用vm.$nextTick的回调函数中。也可以用计算属性和watcher代替
  • beforeDestory:实例销毁之前调用。在这一步,实例仍然完全可用
  • destoryed:实例销毁后调用。该钩子被调用后,对应Vue实例的所有指令都被解绑,所有的事件监听被移除,所有的子实例也都被销毁
  • activated:被 keep-alive 缓存的组件激活时调用
  • deactivated:被 keep-alive 缓存的组件停用时调用

Vue中组件通信:父组件 -> 子组件、子组件 -> 父组件、兄弟组件


  • 父组件通过Prop形式传递值给子组件。单向传递
  • 子组件通过emit事件传递数据给父组件
  • 兄弟组件通信使用vuex

介绍Vuex、使用场景、弊端和如何解决


  • Vuex 是状态管理模式,采用集中式存储管理应用的所有组件状态,每个应用仅仅包含一个 store 实例
  • state:驱动应用的数据源
  • Getter :看做是 store 的计算属性,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖发生了改变才会被重新计算。 Getter 接受 state 作为其第一个参数。接受getters作为第二个参数。可以让getter返回一个函数,来实现给getter传参,此种形式,不会缓存结果
  • Mutation:更改 Vuexstore 中的状态的唯一方法是提交 mutationMutation必须是同步函数 。每个mutation都有一个字符串的事件类型type和一个回调函数handlerhandler就是我们实际进行状态更改的地方,第一个参数是 state,第二个参数是 payload 载荷,载荷应该是一个对象,不能直接调用handler,提交突变commit,实现更改数据源。
    • Mutation 需遵守 Vue 的响应规则
      • 最好提前在你的store中初始化好所有的所需属性
      • 需要在对象上添加新属性时:
        • 使用 Vue.set(obj, 'newProp', 123)
        • 以新对象替换老对象
          • 对象扩展运算符:state.obj = {...state.obj, newProp:123}
          • 使用Object.assign()方法
  • ActionAction提交的是 mutation,而不是直接变更状态;Action 可以包含任意异步状态。Action 函数第一个与 store 实例具有相同方法和属性的context对象,可以使用参数结构来简化代码;可以附加第二个参数payload
    • 可以在组件中使用 this.$store.dispatch('xxx')分发action
    • 使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用,需要现在根节点注入 store

封装一个组件的思路


  • 组件要实现什么功能
  • 组件需要由外部提供哪些数据
  • 组件需要向外部反馈什么信息

盒模型


  • margin外边距、padding内边距、border边框、content内容
  • 标准盒模型:width = content
  • IE8及以下 非标准盒模型 :windth = content + padding + border
  • box-sizing:border-box;

CSS定位


  • static 文档常规流
  • relative 相对文档流原位置进行定位,原位置留下空白
  • absolute 移出正常文档流,不为元素预留空间,相对于最近的一个非 static 定位祖先元素定位
  • fixed 移出正常文档流,不为元素预留空间,相对于屏幕视口 viewport 定位

浮动布局、清除浮动


  • 浮动会脱离正常的文档布局流,形成环绕的效果
  • 清除浮动:
    • clear: both
    • 浮动的父元素添加:overflow:hidden; zoom:1;
    • 使用 :after 伪类,浮动的父元素添加:
        .content:after{
           content:".";
           display:block;
           height:0;
           visibility:hidden;
           clear:both;
         }
       .content{zoom:1;}
      

for...in、for...of、foreach、map有哪些区别


  • for...in:遍历所有可枚举属性,包括原型上的属性和方法,遍历拿到索引或者对象属性,return false 可以结束遍历
  • for...of:遍历,但不包含原型链上的,遍历拿到值,return false 可以结束遍历
  • forEach:接受一个回调函数,进行遍历,不能主动结束遍历
  • map:遍历,返回一个新数组

Vue和JQuery有哪些区别


  • Vue是MVVM架构,数据 和 视图的分离,解耦
  • 以 数据 驱动视图,只关心数据变化, DOM 操作被封装

ES6


  • 块级作用域 let const
  • 模板字符串
  • 函数参数的默认值、rest语法
  • 箭头函数
  • 对象中,键值重名,可简写
  • 解构赋值
  • 扩展运算符
  • 模块化:import 导入模块;export导出模块
  • 异步解决方案:PromiseAsync/await
  • classextendssuper

class语法糖

class Demo{}; 
var demo = new Demo()
// 结果
typeof   Demo   // "function"
Demo === Demo.prototype.constructor  // true
demo.__proto__ === Demo.prototype // true
  • class 是普通构造函数的语法糖,符合JS原型和原型链的规则
  • extends 实现原型链更方便

深拷贝、浅拷贝以及算法,什么时候用


浅拷贝与深拷贝

  • 深拷贝和浅拷贝是针对Object和Array这样的引用数据类型
  • 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存
  • 深拷贝会另外创造一个一模一样的对象,新对象和原对象不共享内存,修改新对象不会改到原对象
  • 浅拷贝的实现方式
    • Object.assign():可以把任意多个源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象,拷贝的是对象的属性的引用,而不是对象本身。当object是一层的时候,是深拷贝
    • Array.prototype.concat() 函数 和 Array.prototype.slice() 函数,两个函数都不会修改原数组,只会返回一个浅复制来了原数组中的元素的一个新数组
  • 深拷贝的实现方式
    • JSON.parse(JSON.stringify()):用 JSON.stringify 将对象转成 JSON 字符串,再用 JSON.parse() 把字符串解析成对象,对象会开辟新的栈,实现深拷贝。不能处理函数。
    • 手写递归遍历实现:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝
    • 函数库:lodash中个的_.cloneDeep()

引用数据类型和基本类型数据


  • 基本数据类型:UndefinedNullBooleanNumberStringSymbol表示独一无二的值
  • 引用类型,统称为Object对象:对象、数组、函数
  • 区别:
    • 存储位置:基本数据类型值存储在栈中;引用类型指针存储在栈中,对象内容存储在堆中
    • 参数传递:基本数据类型传递值的副本,值的改变,互不影响;引用数据类型传递指针,修改对象,相互影响

判断js类型,优缺点


  • typeofnull、数组和对象的typeof均是object
  • instanceofnull instanceof Null // 报错; undefined instanceof undefined // 报错
  • Object.prototype.toString.call():最准确的判断方式,Object.prototype.toString.call('') // [object String]

Promise对象


  • 基本含义
    • Promise 就是一个容器,里面保存着某个未来才会结束的事件的结果
    • 对象的状态不受外界影响。pending进行中、fulfillled已成功、rejected已失败,只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。一旦状态改变,就不会再变,任何时候都可以得到这个结果,pending --> fulfilledpending --> rejected
  • 基本用法
    • promise对象是一个构造函数,用来生成 promise 实例。接受一个函数作为参数,该函数的两个参数分别是 resolvereject。这两个函数有 JavaScript 引擎提供,不用自己部署。
      • resolve 函数的作用是将pending状态变为resolved状态,并将异步操作的结果,作为参数传递出去。如果返回的是另一个Promise,则当前Promise状态被返回的Promise托管
      • reject 函数的作用是将pending状态变为rejected状态,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去,通常是一个 Error 实例。Promise对象的错误具有"冒泡"性质,会一直向后传递,直到被捕获为止;如果没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码
  • finally方法:不管Promise最后状态如何,都会执行的操作

async/await

  • async 函数返回一个Promise对象
  • 当异步函数执行的时候,一旦遇到await命令,就会等待返回结果,得到await后面的异步操作完成,再接着执行函数体后面的语句
  • async 函数内部抛出错误,会导致返回的Promise对象变为reject状态,抛出的错误对象会被catch回调函数接收到
  • await 命令后面是一个Promise对象,返回该对象的结果
  • 任何一个await语句后面的Promise对象变为reject状态,那么整个async函数都会中断执行。如果希望前一个异步的状态不会影响后面的异步操作,可以使用try...catch块或者catch方法
  • 多个await命令后面的异步操作,如果不存在继发关系,最好让他们同时触发
    • await Promise.all([...])
    • const ap = p1(); const bp = p2(); const a = await ap; const b = await bp;

扩展运算符,mapActions使用扩展运算符


  • 扩展运算符是三个点(...),它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列
  • Vuex中的mapActions是一个函数,返回的是一个可遍历的Mapper对象,混入到局部的methods

Vue Router 传递参数


  • 在根实例中注入路由,在任何组件内可通过this.$router访问路由器,通过 this.$route 访问当前路由,this.$route.params路径参数对象,this.$route.queryURl的查询对象
  • 导航
    • 声明式导航:router-link组件,传入 to 属性指定链接
    • 编程式导航:this.$routerpushhistory 栈添加一个新纪录;replace 替换当前的 history 记录;go 前进或后退几步
  • 路由出口:router-view 组件
  • 导航守卫
    • 全局守卫:
      • 全局前置守卫:router.beforeEach((to, from, next) => {...}),当一个导航触发时调用
      • 全局解析守卫 :router.beforeResolve,在导航被确认之前,在所有组件内守卫和异步路由组件被解析之后,被调用
      • 全局后置钩子:router.afterEach,路由被确认,没有next回调
    • 路由独享的守卫:可以在路由配置上直接定义 beforeEnter 守卫
    • 组件内的守卫 :
      • beforeRouteEnter:不能获取实例的this。但是可以通过传一个回调给 next 来访问组件实例
      • beforeRouteUpdate:可以访问组件实例this,路由改变但组件被复用是调用
      • beforeRouteLeave:可以访问组件实例this,导航离开该组件的对应路由时调用。
    • 导航解析流程
      1、导航被触发
      2、在失活的组件里调用离开守卫beforeRouteLeave
      3、调用全局的beforeEach守卫
      4、在重用的组件里调用 beforeRouteUpdate守卫
      5、在路由配置里调用 beforeEnter 守卫
      6、解析异步路由
      7、在被激活的组件里调用 beforeRouteEnter 守卫
      8、调用全局的 beforeResolve 守卫
      9、导航被确认
      10、调用全局的 afterEach 守卫
      11、触发DOM更新
      12、用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数
  • 路由组件传参
    • 导航可以添加paramsquery 参数
    • 使用 props 方式解耦,对于包含命名视图的路由,需要为每个路由添加 props 选项
  • 路由元信息:meta对象,一个路由匹配到的所有路由记录会暴露为$route对象的 $route.matched数组,遍历数组来实现检查路由定义的 meta 字段

flex布局


  • 采用Flex布局的元素,成为 Flex 容器;容器默认存在两根轴,水平的主轴和垂直的交叉轴,项目默认沿主轴排列
  • 容器的属性:
    • flex-direction:主轴的方向即项目的排列方向
    • flex-wrap:项目如何换行
    • justify-content:项目在主轴上的对齐方式
    • align-items:项目在交叉轴上如何对齐
  • 项目的属性:
    • order:定义项目的排列顺序。数值越小,排列越靠前,默认为0
    • flex-grow:定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大;
    • flex-shrink:定义项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
    • flex缩写

单页面应用和SEO


  • SSR
  • Nuxt.js
  • 静态页面等方式

原型规则

  • 所有引用类型(数组、对象、函数)都具有对象特性,即可以自由扩展属性
  • 所有引用类型都有一个隐式原型(__proto__)属性,属性值是一个普通的对象
  • 所有的函数都有一个显式原型(prototype)属性,属性值也是一个普通的对象
  • 所有的引用类型__proto__属性值是指向它的构造函数的prototype属性值。构造函数的prototype都有一个construtor属性,属性值等于构造函数本身
  • 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么就会去它的__proto__(构造函数的prototype)中寻找

JS模块化


  • AMD规范:流行的require.js
    • 自动引入全局 define定义 函数
    • 自动引入全局require引入函数,require只能引入define定义的函数
    • 依赖JS会异步加载
  • CommonJS规范:NodeJS模块化规范
    • module.exports 输出模块
    • require 加载模块
    • 同步加载
  • ES6模块化
    • export 命令用于规定模块对的对外结构
    • export default 命令为模块指定默认输出
    • import 命令用于输入其他模块提供的功能
  • CommonJSES6模块循环加载处理的区别

36、项目性能优化
37、Android和IOS端前端兼容性问题
38、项目难点
39、Vue适合做pc端网站么?优缺点
41、前后端分离如何渲染页面及数据
7、XSS攻击
9、WebGL
14、排序算法
43、有没有关注最新的es特性
44、最近读的一本书,有什么感想
45、webpack的深入配置
46、Vue的双向数据绑定和微信小程序的双向数据绑定有什么异同
24、原生JS
28、高阶函数
29、map函数
30、封装一个V-model组件
31、Vue源码,讲解其中熟悉的一块
32、JsBrage使用及原理
33、学习渠道,及博客等平台关注的人学到了什么

你可能感兴趣的:(前端总结)