vue模板编译
模板编译把用户在标签中写的类似于原生HTML的内容进行编译,把原生HTML的内容找出来,再把非原生HTML找出来,经过一系列的逻辑处理生成渲染函数,也就是render函数的这一段过程称之为模板编译过程
整体渲染流程
模板编译内部流程抽象语法树AST抽象语法树,在计算机科学中,抽象语法树(AbstractSyntaxTree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。之所以说语法是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。比如,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现;而类似于if-condition-then这样的条件跳转语句,可以使用带有两个分支的节点来表示
具体流程
模板解析阶段:将一堆模板字符串用正则等方式解析成抽象语法树AST;
优化阶段:遍历AST,找出其中的静态节点,并打上标记;
代码生成阶段:将AST转换成渲染函数;
export const createCompiler = createCompilerCreator( ...
vue虚拟dom
虚拟DOM简介什么是虚拟dom所谓虚拟DOM,就是用一个JS对象来描述一个DOM节点,像如下示例:
<div class="a" id="b">我是内容</div>
{
tag:'div', // 元素标签
attrs:{ // 属性
class:'a',
id:'b'
},
text:'我是内容', // 文本内容
children:[] // 子元素
}
为什么要有虚拟DOM?我们知道,Vue是数据驱动视图的,数据发生变化视图就要随之更新,在更新视图的时候难免要操作DOM,而操作真实DOM又是非常耗费性能的,这是因为浏览器的标准就把 DOM 设计的非常复杂,所以一个真正的 DOM 元素是非常庞大的,如下所示:
let div = document.createElement('div')
let str = ''
for (const key in div) {
str += key + ''
}
console.log( ...
async、await
async 和 await 在干什么任意一个名称都是有意义的,先从字面意思来理解。async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
async这个问题的关键在于,async 函数是怎么处理它的返回值的!我们当然希望它能直接通过 return 语句返回我们想要的值,但是如果真是这样,似乎就没 await 什么事了。所以,写段代码来试试,看它到底会返回什么:
async function testAsync() {
return "hello async";
}
const result = testAsync();
console.log(result); // Promise { 'hello async' }
——输出的是一个 Promise 对象。
所以,async 函数返回的是一个 Promise 对象。从文档中也可以得到这个信息。async 函数(包含函数语句、函数表达式、 ...
vue双向绑定原理
Vue双向绑定分为两个部分:对象和数组
object双向绑定原理实现方式
通过Object.defineProperty()定义一个observer类,将正常的object转换成一个可观测的object,并且加上了_ob_属性,如果读取了会通过触发get,如果改变了会触发set
// 源码位置:src/core/observer/index.js
/**
* Observer类会通过递归的方式把一个对象的所有属性都转化成可观测对象
*/
export class Observer {
constructor (value) {
this.value = value
// 给value新增一个__ob__属性,值为该value的Observer实例
// 相当于为value打上标记,表示它已经被转化成响应式了,避免重复操作
def(value,'__ob__',this)
if (Array.isArray(value)) {
// 当value为数组时的逻辑
// ...
...
路由模式
路由模式
hash模式这里的 hash 就是指 url 尾巴后的 # 号以及后面的字符。这里的 # 和 css 里的 # 是一个意思。hash 也 称作 锚点,本身是用来做页面定位的,她可以使对应 id 的元素显示在可视区域内。
由于 hash 值变化不会导致浏览器向服务器发出请求,而且 hash 改变会触发 hashchange 事件,浏览器的进后退也能对其进行控制,所以人们在 html5 的 history 出现前,基本都是使用 hash 来实现前端路由的。
window.location.hash = 'qq' // 设置 url 的 hash,会在当前url后加上 '#qq'
var hash = window.location.hash // '#qq'
window.addEventListener('hashchange', function(){
// 监听hash变化,点击浏览器的前进后退会触发
})
history模式已经有 hash 模式了,而且 hash 能兼容到IE8, history 只能兼容到 IE10,为什么还 ...
Promise
promise是什么?1、主要用于异步计算2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果3、可以在对象之间传递和操作promise,帮助我们处理队列
异步回调的问题
之前处理异步是通过纯粹的回调函数的形式进行处理
很容易进入到回调地狱中,剥夺了函数return的能力
问题可以解决,但是难以读懂,维护困难
稍有不慎就会踏入回调地狱 - 嵌套层次深,不好维护
new Promisenew Promise(
function (resolve, reject) {
// 一段耗时的异步操作
resolve('成功') // 数据处理完成
// reject('失败') // 数据处理出错
}
).then(
(res) => {console.log(res)}, // 成功
(err) => {console.log(err)} // 失败
)
Promise.all() 批量执行Promise.all([p1, p2, p3])用于将多个promise实例,包装成一 ...
this词法
ES6添加了一个特殊的词法形式的函数声明,叫做箭头函数,箭头函数在涉及this绑定的行为和普通函数的行为完全不一样,他放弃了所有的普通函数this绑定的规则,取而代之的是用当前的词法作用域覆盖了this原本的值。
var obj = {
count: 0,
cool: function coolFn() {
if(this.count < 1) {
setTimeout(() => {
this.count++;
console.log('awesome?');
},1000);
}
}
}
obj.cool();//awesome?
这个箭头函数中的this直接是cool()的this绑定(因此调用它并不会出错)
它将程序员们经常犯的一个错误给标准化了,也就是混淆了this绑定规则和词法作用域规则。
另一个导致箭头函数不够理想的原因 ...
闭包
闭包是基于词法作用域书写代码时所产生的自然结果
闭包的产生:函数在被定义的地方之外被执行就会产生闭包!!!
function foo() {
var a = 2;
function bar(){
console.log(a);
}
return bar;
}
var bza = foo();
baz(); // 2 这就是闭包!
通常情况下foo执行之后整个内部作用域都会被销毁,因为引擎会销毁不再使用的空间来释放内存空间。
然而闭包会阻止这一情况的发生,会让作用域依然存在,因为bar函数还在使用foo这个作用域,需要给bar在任何时候执行提供支持。所以foo的作用域不会被销毁,bar依然持有对该作用域的引用,这个引用就是闭包!
==无论通过何种手段将内部函数传递到所在的词法作用域以外,他都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包。==
function wait(message){
setTimeout( function timer() { ...
函数中的作用域
函数中的作用域js有基于函数的作用域,每声明一个函数都会为其自身创建一个气泡,可以在附属气泡里获取外层的变量,但是不能从外层气泡中获取附属气泡种的变量
隐藏内部实现
暴露在外面的写法,很不安全
function foo(a) {
b = a + fff(a * 2);
console.log(b * 3);
}
function fff(a) {
return a - 1;
}
var b;
foo(2) // 15
隐藏的写法
function foo(a) {
function fff(a) {
return a - 1;
}
var b;
b = a + fff(a * 2);
console.log(b * 3);
}
foo(2) // 15
规避冲突,可以避免同名标识符之间的冲突,避免被覆盖
方法:
全局命名空间,在全局声明一个独特的变量,通常是一个对象,所有需要暴露给外界的功能都会成为这个对象的属 ...
js数据类型
基本数据类型、引用数据类型
ECMAScript包括两个不同类型的值:基本数据类型和引用数据类型。基本数据类型指的是简单的数据段,引用数据类型指的是有多个值构成的对象。当我们把变量赋值给一个变量时,解析器首先要确认的就是这个值是基本类型值还是引用类型值。JavaScript目前有八种内置类型: Number String Boolean Null Undefined Object Symbol BigInt
常见的基本数据类型Number、String 、Boolean、Null和Undefined。基本数据类型是按值访问的,因为可以直接操作保存在变量中的实际值。示例: var a = 10; var b = a; b = 20; console.log(a); // 10值 上面,b获取的是a值得一份拷贝,虽然,两个变量的值相等,但是两个变量保存了两个不同的基本数据类型值。 b只是保存了a复制的一个副本。所以,b的改变,对a没有影响。
引用类型数据 也就是对象类型Object type,比如:Object 、Array 、Function 、Data ...