(关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导)
这里分享过去一周高级前端进阶群里的学习汇总,每天会在群里给大家发一些资料一起学习,晚上会上传我的笔记,内容以前端基础、源码分析、面试题解为主,如果你上班没时间看,那周末可以好好学习了,弯道超车重在坚持。
如果你也想加群学习,公众号回复加群即可。如果你有好的文章推荐,公众号直接回复即可(文末)。
由于微信不能访问外链,需要点击页尾左下角的“阅读原文”,才能访问本文中的链接。
本周学习汇总
11月9号
-
-
vue-router
默认使用hash 模式来模拟一个完整的 URL,当 URL 改变时,页面不会重新加载。 -
用路由的 history 模式替换hash模式,利用
history.pushState
API 来完成 URL 跳转而无须重新加载页面。const router = new VueRouter({ mode: 'history', routes: [...] })
- 后台需要对路由进行配置
-
-
- 执行上下文总共有三种类型:全局执行上下文、函数执行上下文(只有在函数被调用的时候才会被创建)、Eval 函数执行上下文
- LIFO原则,引擎首次读取脚本时,会创建一个全局执行上下文并将其推入当前的执行栈。每当发生一个函数调用,引擎都会为该函数创建一个新的执行上下文并将其推到当前执行栈的顶端。函数运行完成后,其对应的执行上下文将会从执行栈中弹出,上下文控制权将移到当前执行栈的下一个执行上下文。
- 执行上下文分两个阶段创建:1)创建阶段; 2)执行阶段
- 创建阶段发生三件事:1)确定 this 的值,也被称为 This Binding。2)LexicalEnvironment(词法环境) 组件被创建。3)VariableEnvironment(变量环境) 组件被创建。
-
环境记录 还包含了一个
arguments
对象,该对象包含了索引和传递给函数的参数之间的映射以及传递给函数的参数的长度(数量)。function foo(a, b) { var c = a + b; } foo(2, 3); // arguments 对象 Arguments: {0: 2, 1: 3, length: 2},
- 在创建阶段,函数声明存储在环境中,而变量会被设置为
undefined
(在var
的情况下)或保持未初始化(在let
和const
的情况下)。所以这就是为什么可以在声明之前访问var
定义的变量(尽管是undefined
),但如果在声明之前访问let
和const
定义的变量就会提示引用错误的原因。这就是所谓的变量提升。 - 如果 Javascript 引擎在源代码中声明的实际位置找不到
let
变量的值,那么将为其分配undefined
值。
-
- 对于
Object
来说,它是一个Function
的实例,因为Object instanceof Function // true
;对于Function
来说,它是Object
的实例,因为Function instanceof Object // true
,所以到底是先有Object
还是先有Function
呢? - 一种理解:
Object
基于null
为模板(__proto__
),所以Object.prototype.__proto__ === null
-
new Object
创建一个对象,基于Object.prototype
为模板,所以new Object({}).__proto__ === Object.prototype
// Object new Object().__proto__ === Object.prototype; Object.__proto__ === Function.prototype; Object.prototype.__proto__ === nulll; // Function Function.prototype === Function.__proto__; Function.prototype.__proto__ === Object.prototype; // Foo new Foo().__proto__ === Foo.prototype; Foo.prototype.__proto__ === Object.prototype; Foo.__proto__ === Function.prototype
- 对于
11月8号
-
ES6 系列之 Babel 是如何编译 Class 的(下)(优)
- 寄生组合式继承优点在于只调用一次 Parent 构造函数,避免了在 Parent.prototype 上面创建不必要的、多余的属性,同时原型链还能保持不变。
- ES6的super 关键字表示父类的构造函数,相当于 ES5 的 Parent.call(this)。所以子类只有调用 super 之后,才可以使用 this 关键字
- 子类的
__proto__
属性,表示构造函数的继承,总是指向父类。 - 子类 prototype 属性的
__proto__
属性,表示方法的继承,总是指向父类的 prototype 属性。 - 相比寄生组合式继承,ES6 的 class 多了一个
Object.setPrototypeOf(Child, Parent)
的步骤。 - 语法糖其实用的就是
Object.create()
,第一个参数是新创建的对象,第二个参数表示要添加到新创建对象的属性,注意这里是给新创建的对象即返回值添加属性,而不是在新创建对象的原型对象上添加。 - 首先执行
_inherits(Child, Parent)
,建立 Child 和 Parent 的原型链关系,即Object.setPrototypeOf(Child.prototype, Parent.prototype)
和Object.setPrototypeOf(Child, Parent)
。然后调用Parent.call(this, name)
,根据 Parent 构造函数的返回值类型确定子类构造函数 this 的初始值 _this。最终,根据子类构造函数,修改 _this 的值,然后返回该值。
-
- 场景:有a、b、c三个异步任务,要求必须先执行a,再执行b,最后执行c,且下一次任务必须要拿到上一次任务执行的结果,才能做操作。
-
解决方法一:使用then链式操作
//链式调用 a() .then(function (data) { return b(data) }) .then(function (data) { return c(data) }) .then(function (data) { console.log(data) // abc })
-
解决方法二:构建队列
// 构建队列 function queue(arr) { let sequence = Promise.resolve() arr.forEach(function (item) { sequence = sequence.then(item) }) return sequence } // 执行队列 queue([a, b, c]) .then(data => { console.log(data) // abc })
-
解决方法三:使用async、await构建队列
async function queue(arr) { let res = null for (let promise of arr) { res = await promise(res) } return await res } queue([a, b, c]) .then(data => { console.log(data) // abc })
-
- javascript 可以通过 window.location.hash来读取或改变 #
-
location.href += '#caper';
浏览器滚动到新的位置,但页面不会刷新,改变了浏览器记录,可以通过浏览器上一页
按钮回到原始的位置。 -
HTML 5新增onhashchange 事件,对于不支持onhashchange的浏览器,可以用setInterval监控location.hash的变化。
// 使用方法有三种 window.onhashchange = func; <body onhashchange="func();"> window.addEventListener("hashchange", func, false);
11月7号
-
- 1、React为了性能和复用,采用了事件代理,池,批量更新,跨浏览器和跨平台兼容等思想,将事件监听挂载在document上构造合成事件,在内部模拟了一套捕获冒泡并触发回调函数的机制
- 2、执行顺序:document原生事件 --> 合成事件(冒泡 innerClick --> outerClick)--> window
- 3、如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用setState会异步更新state。除此之外的setState调用会同步执行state,包括通过addEventListener直接添加的事件处理函数,还有通过promise/setTimeout/setInterval产生的异步调用。
- 4、React合成的
SyntheticEvent
采用了池的思想,从而达到节约内存,避免频繁的创建和销毁事件对象的目的。 - 5、React源码中随处可见batch做批量更新,基本上凡是可以批量处理的事情(最普遍的
setState
)React都会将中间过程保存起来,留到最后面才flush掉。 - 6、异步渲染的情况下假如我点了两次按钮,那么第二次按钮响应的时候,可能第一次按钮的handlerA中调用的
setState
还未最终被commit到DOM树上,这时需要把第一次按钮的结果先给flush掉并commit到DOM树,才能够保持一致性。
-
- 1、beforeCreate中拿不到任何数据,在vue实例化之后
- 2、created中已经可以拿到data中的数据了,但是dom还没有挂载,适合ajax请求和页面初始化
- 3、beforeMount 页面挂载之前
- 4、mounted 页面挂载成功,vue实例对象中有template参数选项,则将其作为模板编译成render函数,编译优先级render函数选项 > template选项
- 5、beforeUpdate 页面更新之前
- 6、updated 页面已更新成功
- 7、destroyed 实例化销毁,用于解除绑定
- 8、处理 HTML 标记并构建 DOM 树,处理 CSS 标记并构建 CSSOM 树,将 DOM 与 CSSOM 合并成一个渲染树。根据渲染树来布局,以计算每个节点的几何信息,将各个节点绘制到屏幕上。
-
- 1、一个对象的键只能是字符串或者Symbols,但一个Map的键可以是任意值。、
- 2、通过size属性很容易地得到一个Map的键值对个数,而对象的键值对个数只能手动确认。
- 3、actions是Map对象时,[...actions]可以转换成数组
- 4、在Map中可以用正则类型作为key,这样就有了无限可能
11月6号
-
ES6 系列之 Babel 是如何编译 Class 的(上)
- 1、ES5 的构造函数对应 ES6 的constructor 方法。
- 2、ES6定义的所有方法,都是不可枚举的。
- 3、在方法前加上 static 关键字不会被实例继承,是直接通过类来调用,这个是"静态方法"。
- 4、类和普通构造函数的一个主要区别是类必须使用 new 调用,否则会报错。
- 5、使用 get 和 set 关键字拦截属性默认行为
- 6、Babel 转换通过_classCallCheck检查类是否是通过 new 的方式调用
- 7、静态属性
static bar = 'bar'
转换成Person.bar = 'bar'
- 8、Babel 生成了一个 _createClass 辅助函数,该函数传入三个参数,第一个是构造函数,在这个例子中也就是 Person,第二个是要添加到原型上的函数数组,第三个是要添加到构造函数本身的函数数组,也就是所有添加 static 关键字的函数。该函数的作用就是将函数数组中的方法添加到构造函数或者构造函数的原型中,最后返回这个构造函数。
-
- 1、symbol for 全局共享Symbol
- 2、symbol keyFor 获取全局共享Symbol的key
- 3、Object.getOwnPropertySymbols获取Symbol
- 4、Symbol.hasInstance 内部方法,判断某对象是否为某构造器的实例
- 5、Symbol.toPrimitive内部方法,转换为原始值,加法运算会触发三种类型转换:将值转换为原始值,转换为数字,转换为字符串
-
- 1、DOM事件流中存在着三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段
- 2、.stop:阻止事件冒泡
- 3、.prevent:阻止默认事件
- 4、.capture:添加事件监听器时使用事件捕获模式
- 5、.self:只当在 event.target 是当前元素自身时触发处理函数
- 6、.once:事件只触发一次
- 7、.passive:滚动事件的默认行为 (即滚动行为) 将会立即触发
11月5号
-
使用Promises(优)
- Promise 本质上是一个绑定了回调的对象,而不是将回调传进函数内部。
- 在 JavaScript 事件队列的当前运行完成之前,回调函数永远不会被调用
- 通过 .then 形式添加的回调函数,甚至都在异步操作完成之后才被添加的函数,都会被调用
- 如果想要在回调中获取上个 Promise 中的结果,上个 Promise 中必须要返回结果
- 在一个
.catch
操作之后可以继续使用链式.then
操作 - 通常递归调用一个由异步函数组成的数组时相当于一个 Promise 链式:
Promise.resolve().then(func1).then(func2)
- 传递到then中的函数被置入了一个微任务队列,而不是立即执行,这意味着它是在JavaScript事件队列的所有运行时结束了,事件队列被清空之后才开始执行
- 嵌套的 catch 仅捕捉在其之前同时还必须是其作用域的 failureres,而捕捉不到在其链式以外或者其嵌套域以外的 error。
- 一个好的经验法则是总是返回或终止 Promise 链,并且一旦你得到一个新的 Promise,返回它。
-
- 实现静态资源的按需加载,最大程度的减小首页加载模块体积和首屏加载时间,其提供的Code Splitting(代码分割)特性正是实现模块按需加载的关键方式。
- 将某些第三方基础框架模块(例如:moment、loadash)或者多个页面的公用模块(js、css)拆分出来独立打包加载,通常这些模块改动频率很低,将其与业务功能模块拆分出来并行加载,一方面可以最大限度的利用浏览器缓存,另一方面也可以大大降低多页面系统的代码冗余度。
-
CommonsChunkPlugin
将公共基础库模块
单独打包到一个文件中 - 经常使用webpack的
css-loader
来将css样式导入到js模块中,再使用style-loader
将css样式以<style>
标签的形式插入到页面当中,缺点是无法单独加载并缓存css样式文件,页面展现必须依赖于包含css样式的js模块,从而造成页面闪烁的不佳体验。 - 将js模块当中import的css模块提取出来,需要用到
extract-text-webpack-plugin
- 使用React动态路由来按需加载react组件
-
- Web1.0 到 Web2.0过渡的标志,就是Ajax的出现(2005年)。
- AJAX 即 Asynchronous JavaScript and XML(异步的 JavaScript 与 XML 技术)
- SPA 即单页面,就是页面整体不刷新,不同的页面只改变局部的内容的一种实现方式。
- 一个完整的URI有以下几部分组成:
scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
,以上规则中,只有#
后面的fragment
发生改变时,页面不会重新请求,其它参数变化,均会引起页面的重新请求,而在Js中恰恰还有事件window.onhashchange
能监听到fragment
的变化,于是就利用这个原理来达到一个修改局部内容的操作。#fragment
部分就是对应到Js中的location.hash
的值。 - 一个符合前端工程化要求的方案应该包含以下要素:开发规范、模块化开发、组件化开发、组件仓库、性能优化、部署、开发流程、开发工具
交流
本人Github链接如下,欢迎各位Star
http://github.com/yygmind/blog
我是木易杨,网易高级前端工程师,跟着我每周重点攻克一个前端面试重难点。接下来让我带你走进高级前端的世界,在进阶的路上,共勉!
如果你想加群讨论每期面试知识点,公众号回复[加群]即可
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。