Vue面试专题(未完)

Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend() // ** 收集依赖 ** /
if (childOb) {
childOb.dep.depend() if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter(newVal) {
const value = getter ? getter.call(obj) : val
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
val = newVal
childOb = !shallow && observe(newVal)
dep.notify() /**通知相关依赖进行更新**/
}
})
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']
methodsToPatch.forEach(function (method) { // 重写原型方法
const original = arrayProto[method] // 调用原数组的方法
def(arrayMethods, method, function mutator(...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted) // notify change
ob.dep.notify() // 当调用数组方法后,手动通知视图更新
return result
})
})
this.observeArray(value) // 进行深度监控
update() {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true
} else if (this.sync) {
this.run()
} else {
queueWatcher(this); // 当数据发生变化时会将watcher放到一个队列中批量更新
}
}
export function queueWatcher(watcher: Watcher) {
const id = watcher.id // 会对相同的watcher进行过滤
if (has[id] == null) {
has[id] = true
if (!flushing) {
queue.push(watcher)
} else {
let i = queue.length - 1
while (i > index && queue[i].id > watcher.id) {
i--
}
queue.splice(i + 1, 0, watcher)
} // queue the flush
if (!waiting) {
waiting = true
if (process.env.NODE_ENV !== 'production' && !config.async) {
flushSchedulerQueue()
return
}
nextTick(flushSchedulerQueue) // 调用nextTick方法 批量的进行更新
}
}
}
let timerFunc // 会定义一个异步方法
if (typeof Promise !== 'undefined' && isNative(Promise)) { // promise
const p = Promise.resolve()
timerFunc = () => {
p.then(flushCallbacks)
if (isIOS) setTimeout(noop)
}
isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && ( // MutationObserver
isNative(MutationObserver) || MutationObserver.toString() === '[object MutationObserverConstructor]')) {
let counter = 1
const observer = new MutationObserver(flushCallbacks)
const textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
timerFunc = () => {
counter = (counter + 1) % 2
textNode.data = String(counter)
}
isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined') { // setImmediate
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
timerFunc = () => { // setTimeout
setTimeout(flushCallbacks, 0)
}
} // nextTick实现
export function nextTick(cb ? : Function, ctx ? : Object) {
let _resolve
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
if (!pending) {
pending = true
timerFunc()
}
}
function initComputed(vm: Component, computed: Object) {
const watchers = vm._computedWatchers = Object.create(null) const isSSR = isServerRendering() for (const key in computed) {
const userDef = computed[key]
const getter = typeof userDef === 'function' ? userDef : userDef.get
if (!isSSR) { // create internal watcher for the computed property.
watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions)
}
// component-defined computed properties are already defined on the
// component prototype. We only need to define computed properties defined
// at instantiation here.
if (!(key in vm)) {
defineComputed(vm, key, userDef)
} else if (process.env.NODE_ENV !== 'production') {
if (key in vm.$data) {
warn(`The computed property "${key}" is already defined in data.`, vm)
} else if (vm.$options.props && key in vm.$options.props) {
warn(`The computed property "${key}" is already defined as a prop.`, vm)
}
}
}
}
function createComputedGetter(key) {
return function computedGetter() {
const watcher = this._computedWatchers && this._computedWatchers[key]
if (watcher) {
if (watcher.dirty) { // 如果依赖的值没发生变化,就不会重新求值
watcher.evaluate()
}
if (Dep.target) {
watcher.depend()
}
return watcher.value
}
}
}
function initComputed(vm: Component, computed: Object) {
const watchers = vm._computedWatchers = Object.create(null) const isSSR = isServerRendering() for (const key in computed) {
const userDef = computed[key]
const getter = typeof userDef === 'function' ? userDef : userDef.get
if (!isSSR) { // create internal watcher for the computed property.
watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions)
}
// component-defined computed properties are already defined on the
// component prototype. We only need to define computed properties defined
// at instantiation here.
if (!(key in vm)) {
defineComputed(vm, key, userDef)
} else if (process.env.NODE_ENV !== 'production') {
if (key in vm.$data) {
warn(`The computed property "${key}" is already defined in data.`, vm)
} else if (vm.$options.props && key in vm.$options.props) {
warn(`The computed property "${key}" is already defined as a prop.`, vm)
}
}
}
}
function createComputedGetter(key) {
return function computedGetter() {
const watcher = this._computedWatchers && this._computedWatchers[key]
if (watcher) {
if (watcher.dirty) { // 如果依赖的值没发生变化,就不会重新求值
watcher.evaluate()
}
if (Dep.target) {
watcher.depend()
}
return watcher.value
}
}
}

服务端渲染不支持mounted方法,所以在服务端渲染的情况下统一放到created中
function baseCompile(template: string, options: CompilerOptions) {
const ast = parse(template.trim(), options) // 1.将模板转化成ast语法树
if (options.optimize !== false) { // 2.优化树
optimize(ast, options)
}
const code = generate(ast, options) // 3.生成树
return {
ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
})
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`;
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
const startTagOpen = new RegExp(`^<${qnameCapture}`); // 标签开头的正则 捕获的内容是 标签名
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`); // 匹配标签结尾的 </div>
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+| ([^\s"'=<>`]+)))?/; // 匹配属性的
const startTagClose = /^\s*(\/?)>/; // 匹配标签结束的 >
let root;
let currentParent;
let stack = []
function createASTElement(tagName, attrs) {
return {
tag: tagName,
type: 1,
children: [],
attrs,
parent: null
}
}
function start(tagName, attrs) {
let element = createASTElement(tagName, attrs);
if (!root) {
root = element;
}
currentParent = element;
stack.push(element);
}
function chars(text) {
currentParent.children.push({
type: 3,
text
})
}
function end(tagName) {
const element = stack[stack.length - 1];
stack.length--;
currentParent = stack[stack.length - 1];
if (currentParent) {
element.parent = currentParent;
currentParent.children.push(element)
}
}
function parseHTML(html) {
while (html) {
let textEnd = html.indexOf('<');
if (textEnd == 0) {
const startTagMatch = parseStartTag();
if (startTagMatch) {
start(startTagMatch.tagName, startTagMatch.attrs);
continue;
}
const endTagMatch = html.match(endTag);
if (endTagMatch) {
advance(endTagMatch[0].length);
end(endTagMatch[1])
}
}
let text;
if (textEnd >= 0) {
text = html.substring(0, textEnd)
}
if (text) {
advance(text.length);
chars(text);
}
}
function advance(n) {
html = html.substring(n);
}
function parseStartTag() {
const start = html.match(startTagOpen);
if (start) {
const match = {
tagName: start[1],
attrs: []
}
advance(start[0].length);
let attr, end
while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
advance(attr[0].length);
match.attrs.push({
name: attr[1],
value: attr[3]
})
}
if (end) {
advance(end[0].length);
return match
}
}
}
} // 生成语法树
parseHTML(`<div id="container"><p>hello<span>zf</span></p></div>`);
function gen(node) {
if (node.type == 1) {
return generate(node);
} else {
return `_v(${JSON.stringify(node.text)})`
}
}
function genChildren(el) {
const children = el.children;
if (el.children) {
return `[${children.map(c=>gen(c)).join(',')}]`
} else {
return false;
}
}
function genProps(attrs) {
let str = '';
for (let i = 0; i < attrs.length; i++) {
let attr = attrs[i];
str += `${attr.name}:${attr.value},`;
}
return `{attrs:{${str.slice(0,-1)}}}`
}
function generate(el) {
let children = genChildren(el);
let code = `_c('${el.tag}'${ el.attrs.length? `,${genProps(el.attrs)}`:'' }${ children? `,${children}`:'' })`;
return code;
} // 根据语法树生成新的代码
let code = generate(root);
let render = `with(this){return ${code}}`; // 包装成函数
let renderFn = new Function(render);
console.log(renderFn.toString());
const VueTemplateCompiler = require('vue-template-compiler');
let r1 = VueTemplateCompiler.compile(`<div v-if="true"><span v-for="i in 3">hello</span></div>`);
/**
with(this) { return (true) ? _c('div', _l((3), function (i) { return _c('span', [_v("hello")]) }), 0) : _e() }
*/
const VueTemplateCompiler = require('vue-template-compiler');
let r2 = VueTemplateCompiler.compile(`<div v-show="true"></div>`);
/** with(this) { return _c('div', { directives: [{ name: "show", rawName: "v-show", value: (true), expression: "true" }] }) }*/
// v-show 操作的是样式 定义在platforms/web/runtime/directives/show.js
bind(el: any, {
value
}: VNodeDirective, vnode: VNodeWithData) {
vnode = locateNode(vnode)
const transition = vnode.data && vnode.data.transition
const originalDisplay = el.__vOriginalDisplay = el.style.display === 'none' ? '' : el.style.display
if (value && transition) {
vnode.data.show = true
enter(vnode, () => {
el.style.display = originalDisplay
})
} else {
el.style.display = value ? originalDisplay : 'none'
}
}
const VueTemplateCompiler = require('vue-template-compiler');
let r1 = VueTemplateCompiler.compile(`<div v-if="false" v-for="i in 3">hello</div>`);
/** with(this) { return _l((3), function (i) { return (false) ? _c('div', [_v("hello")]) : _e() }) }*/
console.log(r1.render);
function $createElement(tag, data, ...children) {
let key = data.key;
delete data.key;
children = children.map(child => {
if (typeof child === 'object') {
return child
} else {
return vnode(undefined, undefined, undefined, undefined, child)
}
}) return vnode(tag, props, key, children);
}
export function vnode(tag, data, key, children, text) {
return {
tag, // 表示的是当前的标签名
data, // 表示的是当前标签上的属性
key, // 唯一表示用户可能传递
children,
text
}
}


Vue面试专题(未完)的更多相关文章
- Python面试2未完待续
Python面试重点(基础篇) 注意:只有必答题部分计算分值,补充题不计算分值. 第一部分 必答题(每题2分) 简述列举了解的编程语言及语言间的区别? c语言是编译型语言,运行速度快,但翻译时间长py ...
- vue 大概流程(未完)
规划组件结构 编写对应路由 具体写每个组件功能
- 太原面经分享:如何在vue面试环节,展示你晋级阿里P6+的技术功底?
前言 一年一度紧张刺激的高考开始了,与此同时,我也没闲着,奔走在各大公司的前端面试环节,不断积累着经验,一路升级打怪. 最近两年,太原作为一个准二线城市,各大互联网公司的技术栈也在升级换代,假如你在太 ...
- 手撕面试官系列(六):并发+Netty+JVM+Linux面试专题
并发面试专题 (面试题+答案领取方式见侧边栏) 现在有 T1.T2.T3 三个线程,你怎样保证 T2 在 T1 执行完后执行,T3 在 T2 执行完后执行? 在 Java 中 Lock 接口比 syn ...
- php面试专题---mysql数据库分库分表
php面试专题---mysql数据库分库分表 一.总结 一句话总结: 通过数据切分技术将一个大的MySQLServer切分成多个小的MySQLServer,既攻克了写入性能瓶颈问题,同一时候也再一次提 ...
- php面试专题---MySQL分区
php面试专题---MySQL分区 一.总结 一句话总结: mysql的分区操作还比较简单,好处是也不用自己动手建表进行分区,和水平分表有点像 1.mysql分区简介? 一个表或索引-->N个物 ...
- php面试专题---12、JavaScript和jQuery基础考点
php面试专题---12.JavaScript和jQuery基础考点 一.总结 一句话总结: 比较常考察的是JavaScript的HTML样式操作以及jQuery的选择器和事件.样式操作. 1.下列不 ...
- php面试专题---10、网络协议考点
php面试专题---10.网络协议考点 一.总结 一句话总结: 网络的考点其实就是这些:常见状态码,常见协议,osi七层模型,http和https 1.HTTP/1.1中,状态码200.301.304 ...
- php面试专题---5、流程控制考点
php面试专题---5.流程控制考点 一.总结 一句话总结: 看代码不要先看函数里面的内容,要用的时候再去看:注意静态,注意变量作用域,php中的内置函数需要去归类总结,就是太容易忘记了 1.写出如下 ...
随机推荐
- C++常见STL介绍
栈 :FILO 栈(stack)又名堆栈,它是一种线性表,是一个后进先出的数据结构. 使用时须加上头文件:#include<stack> 允许进行插入和删除操作的一端称为栈顶(top),另 ...
- 20191310Lee_yellow缓冲区溢出实验
缓冲区溢出实验 1.什么是缓冲区溢出 缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况.这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段.这一漏洞的出现是由于数据 ...
- jmeter 插件安装之阶梯式压测(五)
一.Jmeter插件安装 jmeter-plugins-manager-1.4.jar 下载地址:https://jmeter-plugins.org/install/Install/ 下载之后将插件 ...
- 【Python+postman接口自动化测试】(3)什么是接口测试?
什么是接口测试? 接口测试是测试系统组件间接口的一种测试.接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点.测试的重点是要检查数据的交换.传递和控制管理过程,以及系统间的相互逻辑依 ...
- [python]django的mode设置表结构和serializers序列化数据
框架使用的库版本 python3.6.5 Django-2.0.6 djangorestframework-3.8.2 mysqlclient-1.3.12 1.项目结构声明,数据库在setting. ...
- Buildroot 用户手册 (中文)
文章目录 I. Getting started 1. About Buildroot 2. System requirements 2.1. Mandatory packages 2.2. Optio ...
- css--元素居中常用方法总结
前言 元素居中是日常开发和学习中最常见的问题,同时也是面试中经常考察的知识点,本文来总结一下这方面的知识点. 正文 1.水平居中 (1)子父元素宽度固定,子元素设置 margin:auto,并且子元素 ...
- 第12组 Alpha冲刺 (1/6)
过去两天完成了哪些任务 文字描述 静态页面代码编写以及一些点击事件 展示GitHub当日代码/文档签入记录 接下来的计划 1.继续学习echarts 2.编写所需要的图表代码 还剩下哪些任务 1.图表 ...
- 用C++实现俄罗斯方块(Tetris)游戏
我是一个C++初学者,控制台实现了一个俄罗斯方块游戏. 代码如下: //"俄罗斯方块"V1.0 //李国良于2017年1月20日编写完成 #include <iostream ...
- 1组-Alpha冲刺-3/6
一.基本情况 队名:震震带着六菜鸟 组长博客:https://www.cnblogs.com/Klein-Wang/p/15544334.html 小组人数:7人 二.冲刺概况汇报 王业震 过去两天完 ...