一、闭包

《JavaScript高级程序设计》:

闭包是指有权访问另一个函数作用域中的变量的函数

《JavaScript权威指南》:

1、函数嵌套函数

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

3、参数和变量不会被垃圾回收机制回收
闭包更准确的说是一项技术或者一个特性
闭包的主要是为了解决ES6之前JavaScript只有全局作用域和局部作用域的问题,解决全局作用域下变量易被污染,函数作用域下由于JavaScript垃圾回收机制函数调用结束后变量随之销毁的问题。通过函数嵌套并将返回的函数赋值给一个变量,形成一个作用域链,使得被赋值的变量不被销毁之前函数也不会销毁,这种技术或者特性应该被称为“闭包”。
应用场景
1、防抖节流
2、创建私有函数、变量或方法
3、给某些(框架等)定义好的函数额外传参,如element-ui可搜索输入框的fetch-suggestions方法
getName(id) {
    return (val, callback) => {
      let result = []
      if (val === '' || !val) { // 还没输入,则不发请求
        return callback(result)
      }
    }
},
缺陷

1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2、可能造成内存泄漏,部分人认为IE浏览器会,新的不会,部分人认为会。

要知道内存泄漏的原因——通常来讲是引用无法被释放。

比如你构造了一个lambda,其会持有一份上下文引用,如果这个lambda无法被释放的话,其持有的上下文引用也无法被释放,这样就会造成内存泄漏,久而久之就会撑爆客户的内存。因此要避免「局部构造,全局持有」的情况,这样就不容易出现内存泄漏,通常随着局部上下文的销毁,其中的所有资源都能被回收。但如果出现了「局部构造,全局持有」的情况,则就算局部上下文被「销毁」,也无法回收其资源,比较常见的例子就是你在某个组件里mounted时创建了一个定时器,并且没有unmounted 或 beforeDestroy 时销毁这个定时器,这就会造成内存泄漏。setimeout会自动销毁,但interval不会,interval会一直触发,直到被销毁。
内存泄漏 —— 王一鹏

二、BFC

定义
BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。
Formatting Context

Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。

BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。
BFC的布局规则
*   内部的Box会在垂直方向,一个接一个地放置。

*   Box垂直方向的距离由margin决定。属于**同一个**BFC的两个相邻Box的margin会发生重叠。

*   每个盒子(块盒与行盒)的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。

*   BFC的区域不会与float box重叠。

*   BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。

*   计算BFC的高度时,浮动元素也参与计算。
创建BFC
*   1、float的值不是none。
*   2、position的值不是static或者relative。
*   3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
*   4、overflow的值不是visible
应用场景
1、清除浮动
2、两栏自适应布局
3、避免外边距塌陷
引自 https://blog.csdn.net/sinat_3...

三、清除浮动

定义
在非IE浏览器下,当容器的高度为auto,且容器的内容中有浮动(float为left或right)的元素,在这种情况下,容器的高度不能自动伸长以适应内容的高度,使得内容溢出到容器外面而影响(甚至破坏)布局的现象,这种现象叫做浮动溢出。为了防止这个现象的出现而进行的CSS处理,成为CSS清除浮动。
清除浮动的方法可以分为两类:
1、是利用clear属性,在浮动元素末尾添加一个带有clear:both属性的空元素
2、是触发浮动元素父元素的BFC,使得该父元素可以包含浮动元素。
使用带clear属性的空元素
1、在浮动元素后面使用一个空元素比如<div class="clear"></div>,并在CSS中赋予.clear { clear: both;}属性即可清除浮动
2、使用CSS的:after伪元素。给浮动元素的容器添加一个clearfix的class,然后给这个class添加一个:after伪元素实现元素末尾添加一个看不到的块元素清除浮动
/* 浮动元素的父元素 */
.clearfix {
  /* 兼容IE,触发hasLayout*/
  zoom: 1;
}
/*  添加一个块级的空元素,并且设置clear属性 */
.clearfix:after {
  content: '';
  display: block;
  clear: both;
}
3、给浮动元素后面的元素添加clear属性
触发父元素的BFC
1、设置浮动元素的父元素的overflow: hidden或overflow: auto。触发BFC。另外在IE6中还需要触发hasLayout,例如为父元素设置宽高或者zoom:1。
2、给浮动元素的容器也添加浮动,整体浮动,不推荐
引自 https://www.yuque.com/4amgodv...

四、<script>的defer和async

script标签用于加载脚本与执行脚本,在前端开发中可以说是非常重要的标签了。直接使用script脚本的话,html会按照顺序来加载并执行脚本,在脚本加载&执行的过程中,会阻塞后续的DOM渲染。

defer定义
`defer`属性规定是否对脚本执行进行延迟,直到页面加载为止。如果`script`标签设置了该属性,则浏览器会异步的下载该文件并且不会影响到后续`DOM`的渲染;如果有多个设置了`defer`的`script`标签存在,则会按照顺序执行所有的`script`。`defer`脚本会在文档渲染完毕后,`DOMContentLoaded`事件调用前执行。
async定义
`async`的设置,会使得`script`脚本异步的加载并在允许的情况下执行`async`的执行,并不会按着`script`在页面中的顺序来执行,而是谁先加载完谁执行。
区别
async属性是HTML5新增的。作用和defer类似,但是它将在下载后尽快执行,不能保证脚本会按顺序执行。它们将在onload 事件之前完成。
引自 https://www.cnblogs.com/jiasm...

五、cookie储存及其原理

https://blog.csdn.net/chao821...

六、sessionStorage、localStorage、cookie异同

  • 存储位置: cookie是网站为了标识用户身份而保存在客户端中的数据,它始终在同源的HTTP请求中携带,也就是会在客户端与服务端之间来回传递。而sessionStorage和localStorage不会主动把数据发送给服务端,仅在本地保存。
  • 存储大小: cookie数据大小不能超过4K,而sessionStorage和localStorage虽然也有存储大小的限制,但是远比cookie大,可以达到5M甚至更大。
  • 生命周期: cookie在设置的过期时间之前一直有效,即使窗口或者浏览器关闭,sessionStorage数据在当前浏览器关闭后自动删除,localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除。
  • 共享:cookie在同源和符合path规则的文档之间共享,而sessionStorage不能共享,localStorage在同源的文档之间共

七、判断数据类型及数组的方法

typeof
typeof 表达式
typeof 1; // number
结果为字符串   
  • 对于基本类型,除 null 以外,均可以返回正确的结果。
  • 对于引用类型,除 function 以外,一律返回 object 类型。
  • 对于 null ,返回 object 类型。
  • 对于 function 返回  function 类型
  • 不可判断数组
instanceof
instanceof 检测的是原型,表达式为:A instanceof B。如果 A 是 B 的实例,则返回 true,否则返回 false。

数组:[] instanceof Array

constructor
A.constructor === B   

1. null 和 undefined 是无效的对象,因此是不会constructor 存在的,这两种类型的数据需要通过其他方式来判断。
2. 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object。

数组:[].constructor === Array

toString
Object.prototype.toString.call(value);

返回格式为 [object XXX]
数组:Object.prototype.toString.call([]) 【object Array】

isArray()
function myFunction() {
    var fruits = ["Banana", "Orange", "Apple", "Mango"];
    var x = document.getElementById("demo");
    x.innerHTML = Array.isArray(fruits);
}

isArray() 方法用于判断一个对象是否为数组。

如果对象是数组返回 true,否则返回 false。

等等。。。

八、拷贝

最简单的深拷贝。。。吧:

// 克隆传入的对象
  easyClone(entity) {
    return JSON.parse(JSON.stringify(entity))
  },

缺点:拷贝其他引用类型、拷贝函数、循环引用等情况无法实现。因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。

let arr = [1, 3, {
    username: ' kobe'
},function(){}];
let arr4 = JSON.parse(JSON.stringify(arr));
arr4[2].username = 'duncan'; 
console.log(arr, arr4)

image.png

浅拷贝
1、let obj2 = Object.assign({}, obj1)
2、let obj2= {... obj1}
3、let arr2 = arr.concat()
4、let arr3 = arr.slice()
深拷贝

不包含set map function 正则版

function forEach(array, iteratee) {
    let index = -1
    const length = array.length
    while (++index < length) {
        iteratee(array[index], index)
    }
    return array;
}
function isObject(target) {
    const type = typeof target
    return target !== null && (type === 'object' || type === 'function')
}
function clone(target, map = new WeakMap()) {

    // 克隆原始类型
    if (!isObject(target)) {
        return target
    }
    //undefind
    if (typeof target === 'undefined') return null
    
    // 初始化
    const isArray = Array.isArray(target)
    let cloneTarget = isArray ? [] : {}


    // 防止循环引用
    if (map.get(target)) {
        return map.get(target);
    }
    map.set(target, cloneTarget);

    // 克隆对象和数组
    const keys = isArray ? undefined : Object.keys(target)
    forEach(keys || target, (value, key) => {
        if (keys) {
            key = value
        }
        cloneTarget[key] = clone(target[key], map);
    });

    return cloneTarget
}
部分引自 https://juejin.cn/post/684490...
部分引自 https://segmentfault.com/a/11...

九、事件委托的优点

1、节省内存占用,减少事件注册
2、新增子元素时无需再对其绑定事件,适合动态添加元素

十、vue 组件通信方式

1、props/$emit
2、$children/$parent
3、provide/inject
4、ref
5、eventBus
6、loaclStorge/sessionStorge
7、$attrs/$listeners
8、VueX
详见 https://juejin.cn/post/684490...
详见 https://segmentfault.com/a/11...
总结

常见使用场景可以分为三类:

  • 父子组件通信: props; $parent / $children; provide / inject ; ref ; $attrs / $listeners
  • 兄弟组件通信: eventBus ; vuex
  • 跨级通信: eventBus;Vuex;provide / inject$attrs / $listeners

十一、服务端渲染和客户端渲染

详见 https://www.cnblogs.com/zhuzh...

十二、herf和src区别

总结:href用于建立当前页面与引用资源之间的关系(链接),而src则会替换当前标签。遇到href,页面会并行加载后续内容;而src则不同,浏览器需要加载完毕src的内容才会继续往下走。
引自 https://www.cnblogs.com/kuai-...

十三、Map和Set

数组方法 map()

1、 map()

对数组的每一项都运行给定的函数,返回每次函数调用的结果组成一个新数组
var numbers = [1, 5, 10, 15];
var doubles = numbers.map(function(x) {
   return x * 2;
});
// doubles is now [2, 10, 20, 30]
// numbers is still [1, 5, 10, 15]
数据结构 Map()和Set()

1、Map()

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。
但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以作键。
Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。Map 的属性和方法:

(1)size返回 Map 的元素个数

(2)set增加一个新元素,返回当前 Map

(3)get返回键名对象的键值

(4)has检测 Map 中是否包含某个元素,返回 boolean 值

(5)clear 清空集合,返回 undefined
2、Set()

ES6 提供了新的数据结构 Set(集合)。
它类似于数组,但成员的值都是唯一的,集合实现了 iterator 接口.
所以可以使用『扩展运算符』和『for…of…』进行遍历,集合的属性和方法:

1) size 返回集合的元素个数

2) add 增加一个新元素,返回当前集合

5)delete 删除元素,返回 boolean 值

6)has检测集合中是否包含某个元素,返回 boolean 值

7)clear 清空集合,返回 undefined

十四、vue 组件化

定义
用户对项目程序中具有独立逻辑、具有复用性的功能模块单独提取出来进行封装,这就是组件化的定义。组件化开发能大幅提高应用开发效率、测试性、复用性等。
优点
  • 组件是独立和可复用的代码组织单元。组件系统是 Vue 核心特性之一,它使开发者使用小型、独立和通常可复用的组件构建大型应用;
  • 组件化开发能大幅提高应用开发效率、测试性、复用性等;
  • 组件使用按分类有 :页面组件、业务组件、通用组件;
  • vue的组件是基于配置的,我们通常编写的组件是组件配置而非组件,框架后续会生成其构造函数,它们基于VueComponent,扩展于Vue;
  • vue中常见组件化技术有: 属性prop,自定义事件,插槽等,它们主要用于组件通信、扩展等;
  • 合理的划分组件,有助于提升应用性能;
  • 组件应该是高内聚、低耦合的;
  • 遵循单向数据流的原则。
引自 https://blog.csdn.net/qq_3678...

十五、vue 响应式原理

初始化

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter

收集依赖

每个组件都对应一个Watcher,当外界通过Watcher读取数据时,便会触发getter从而将Watcher添加到依赖中,哪个Watcher触发了getter,就把哪个Watcher收集到Dep中。当数据发生变化时,会循环依赖列表,把所有的Watcher都通知一遍。

派发更新

在修改对象的值的时候,会触发对应的settersetter通知之前依赖收集得到的 Dep 中的每一个 Watcher,告诉它们自己的值改变了,需要重新渲染视图。这时候这些 Watcher就会开始调用 update 来更新视图。

部分引自 https://cn.vuejs.org/v2/guide...
部分引自 https://www.cnblogs.com/funde...
参考 https://zhuanlan.zhihu.com/p/...

十六、浏览器同源、跨域

同源
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说 Web 是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

所谓同源是指:域名、协议、端口相同。

跨域

1、AJAX 跨域

*   JSONP
*   WebSocket
*   CORS

2、其他

* document.domain 跨域
* window.name 跨域
* location.hash 跨域
* postMessage 跨域
参考 http://www.ruanyifeng.com/blo...
参考 http://www.ruanyifeng.com/blo...
参考 https://www.cnblogs.com/laixi...
参考 https://www.cnblogs.com/2050/...

十七、重绘回流

https://segmentfault.com/a/11...

十八、防抖节流

https://mp.weixin.qq.com/s/qy...

十九、this指向

https://mp.weixin.qq.com/s/hY...

二十、从输入url到页面呈现

在输入URL后,浏览器首先要找到这个URL中的域名对应的IP地址。浏览器首先会从缓存当中查找,如果缓存中没有会到系统的hosts文件中查找,如果hosts文件中没有则查询DNS服务器。找到IP地址后,浏览器会根据这个IP地址和对应的端口号,构造一个HTTP请求,并且将请求封装在一个TCP包中,这个TCP包依次会经过传输层,网络层,数据链路层,物理层到达服务器,服务器解析这个请求来作出响应,返回相应的HTML给浏览器,浏览器根据这个HTML来构建DOM树,在DOM树的构建过程中如果遇到JS脚本和外部JS链接,则会停止构建DOM树来下载和执行相应的代码,这就是为什么推荐JS代码应该放在HTML代码后面。之后根据外部样式,内部样式,内联样式构建一个CSS对象模型树CSSOM树,构建完成后与DOM树合并为渲染树,这里主要做的是排除非视觉节点,比如script,meta标签和排除display为none的节点。之后进行布局。布局主要是确定各个元素的位置和尺寸,然后是渲染页面。因为HTML文件中会含有图片,视频,音频等资源,在解析DOM的时候,遇到这些都会并行下载。浏览器对每个域的并行下载数量有一定的限制,一般是4-6个
https://www.yuque.com/4amgodv...

二十一、前端性能优化

https://www.cnblogs.com/lanxi...

二十二、flex

http://www.ruanyifeng.com/blo...

二十三、vue 中不能使用箭头函数的情况

1.不应该使用箭头函数来定义一个生命周期方法
2.不应该使用箭头函数来定义 method 函数
3.不应该使用箭头函数来定义计算属性函数
4.不应该对 data 属性使用箭头函数
5.不应该使用箭头函数来定义 watcher 函数

原因:箭头函数绑定了父级作用域的上下文,this 将不会按照期望指向 Vue 实例。也就是说,你不能使用this来访问你组件中的data数据以及method方法了。this将会指向undefined。

傅鹏翔
1 声望0 粉丝