第1章 课程介绍
1-1 导学
课程概述
- 做什么?— 讲解前端 JS 高级面试题
- 哪些部分?— 高级基础, 框架原理, app混合开发
- 技术?— JS、ES6、虚拟DOM、vue、React、hybrid
知识点介绍
- 基础知识:ES6 常用语法、原型高级应用、异步全面讲解
- 框架原理:虚拟 DOM、MVVM vue、组件化 React
- 混合开发:hybrid、hybrid vs H5、前端客户端通讯
课程安排
- 高级基础
- ES6 常用语法:Class Module Promise 等
- 原型高级应用:结合 jQuery 和 zepto 源码
- 异步全面讲解:从原理到 jQuery 再到 Promise
- 框架原理
- 虚拟 DOM:存在价值,如何使用,diff 算法
- vue:MVVM,vue 响应式、模板解析、渲染
- React:组件化,JSX,vdom,setState
- 对比:有主见,自圆其说
- App混合开发
- hybrid:基础、和 h5 对比,上线流程
- 通讯:通讯原理,JS-Bridge 封装
讲授方式
- 先出面试题,带领大家思考
- 通过题目引出知识点,扩充讲解知识体系
- 最后通过学到的知识点,解答题目
课程收获
- 从深度和广度都扩充了自己的知识体系
- 学会如何高效学习
- 深入理解常用框架的实现原理和 hybrid 应用
1-2 课程重要提示
1-3 架构-题目
ES6
模块化的使用和编译环境?
Class 与 JS 构造函数的区别?
Promise 的用法?
ES6 其他常用功能?
异步
什么是单线程,和异步有什么关系?
什么是 event-loop?
目前 JS 解决异步的方案有哪些?
如果只用 jquery 如何解决异步?
Promise 的标准?
async/await 的使用?
原型
原型如何实际应用?
原型如何满足扩展?
vdom
什么是 vdom,为何要用 vdom?
vdom如何使用,核心函数有哪些?
了解 diff 算法吗?
MVVM
之前使用 jquery 和现在使用 Vue 或 React 框架的区别?
你如何理解MVVM?
Vue 如何实现响应式?
Vue 如何解析模版?
介绍 Vue 的实现流程?
组件化
对组件化的理解?
JSX 是什么?
JSX 和 vdom 什么关系?
简述 React 的 setState?
简述自己如何比较 React 和 Vue?
hybrid
hybrid 是什么,为何要用hybrid?
hybrid 如何更新上线?
hybrid 和 h5 有何区别?
JS 如何与客户端通信?
第2章 ES6 语法
2-1 开始
ES6
- 开发环境已经普及使用
- 浏览器环境却支持不好(需要开发环境编译)
- 内容很多,重点了解常用语法
- 面试:开发环境的使用 + 重点语法的掌握
题目
- ES6 模块化如何使用,开发环境如何打包?
- Class 和普通构造函数有何区别?
- Promise 的基本使用和原理?
- 总结一下 ES6 其他常用功能?
2-2 模块化
【题目】
ES6 模块化如何使用,开发环境如何打包?
【知识点】
1. 模块化的基本语法
- export 语法
// util1.js
export default {
a: 100
};
// util2.js
export function fn1() {
alert('fn1');
};
export function fn2() {
alert('fn2');
};
- import 语法
// index.js
import util1 from './util1.js';
import { fn1, fn2 } from './util2.js';
console.log(util1);
fn1();
fn2();
2. 开发环境配置
babel
- 安装 babel
1. 电脑有 node 环境,运行 npm init
2. npm install --save-dev babel-core babel-preset-es2015 babel-preset-latest
3. 创建 .babelrc 文件,输入以下内容:
{
"presets": ["es2015", "latest"],
"plugins": []
}
4. sudo npm install -g babel-cli
5. babel --version
- 使用 babel
1. 创建:./src/index.js
2. 内容:[1, 2, 3].map(item => item + 1);
3. 运行:babel ./src/index.js
webpack
- 安装 webpack
此处 babel-loader 需要指定版本,不然掉坑
https://www.cnblogs.com/jiebba/p/9618930.html - 使用 webpack
1. npm install webpack webpack-cli babel-loader@^7.1.2 --save-dev
2. 配置 webpack.config.js,输入以下内容:
module.exports = {
entry: './src/index.js',
output: {
path: __dirname,
filename: './build/bundle.js'
},
module: {
rules: [{
test: /\.js?$/,
exclude: /{node_modules}/,
loader: 'babel-loader'
}]
}
}
3. 配置 package.json 中的 scripts
"scripts": {
"start": "webpack"
}
4. 运行 npm start
5. 创建:index.html
6. http-server -p 8881
7. 访问 http://localhost:8881/index.html
rollup
- 安装 rollup
https://www.rollupjs.com/guide/tutorial rollup 中文网
1. npm init
2. npm i rollup rollup-plugin-node-resolve rollup-plugin-babel@^3.0.3 babel-plugin-external-helpers babel-preset-latest babel-core --save-dev
3. 配置 .babelrc
{
"presets": [
["latest", {
"es2015": {
"modules": false
}
}]
],
"plugins": ["external-helpers"]
}
4. 配置 rollup.config.js
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
export default {
input: 'src/index.js',
output: {
file: 'build/bundle.js',
format: 'cjs'
},
plugins: [
resolve(),
babel({
exclude: 'node_modules/**'
})
]
};
- 使用 rollup
1. 将 webpack 环境的 JS 代码拷贝过来
2. 修改 package.json 的 scripts
"scripts": {
"start": "rollup -c rollup.config.js"
}
3. 运行 npm start
- 关于工具
rollup 功能单一,webpack 功能强大
参考设计原则和《Linux/Unix设计思想》
工具要尽量功能单一,可集成,可扩展
wangEditor 用的 gulp + rollup
3. 关于 JS 众多模块化标准
- 没有模块化
- AMD 成为标准,require.js (也有 CMD)
- 前端打包工具,是的 nodejs 模块化可以被使用
- ES6 出现,想统一现在所有模块化标准
- nodejs 积极支持,浏览器尚未统一
- 你可以自造 lib ,但是不要自造标准!!!
【解答】
- 语法: import export (注意有无 default)
- 环境: babel 编译 ES6 语法,模块化可用 webpack 和 rollup
- 扩展: 说一下自己对模块化标准统一的期待
2-9 class
【题目】
Class 与 JS 构造函数的区别?
- Class 在语法上更加贴合面向对象的写法
- Class 实现继承更加易读、易理解
- 更易于写 java 等后端语言的使用
- 本质还是语法糖,使用 prototype
【知识点】
JS 构造函数
function MathHandle(x, y) {
this.x = x;
this.y = y;
}
MathHandle.prototype.add = function () {
return this.x + this.y;
};
var m = new MathHandle(1, 2);
console.log(m.add());
// typeof MathHandle // "function"
// MathHandle === MathHandle.prototype.constructor // true
// m.__proto__ === MathHandle.prototype // true
Class 基本语法
class MathHandle {
constructor (x, y) {
this.x = x;
this.y = y;
}
add() {
return this.x + this.y;
}
}
const m = new MathHandle(1, 2);
console.log(m.add());
// typeof MathHandle // "function"
// MathHandle === MathHandle.prototype.constructor // true
// m.__proto__ === MathHandle.prototype // true
语法糖
class MathHandle {
// ...
}
typeof MathHandle // "function"
MathHandle === MathHandle.prototype.constructor // true
继承
- 继承 - JS
ES6 之前的继承,是把低级构造函数的原型,赋值成高级构造函数的实例这种方式来实现的
// 动物
function Animal() {
this.eat = function () {
console.log('animal eat');
}
}
// 狗
function Dog() {
this.bark = function () {
console.log('dog bark');
}
}
// 绑定原型,实现继承
Dog.prototype = new Animal();
// 哈士奇
var hashiqi = new Dog();
hashiqi.eat(); // animal eat
hashiqi.bark(); // dog bark
- 继承 - Class
// 动物
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} eat`);
}
}
// 狗
class Dog extends Animal {
constructor(name) {
super(name);
this.name = name;
}
say() {
console.log(`${this.name} say`);
}
}
// 哈士奇
const dog = new Dog('哈士奇');
dog.say(); // 哈士奇 say
dog.eat(); // 哈士奇 eat
【解答】
class Ad extends Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render() {
return (
Hello, World!
)
}
componentDidMount() {
}
}
2-13 Promise
【题目】
Promise 的用法?
【知识点】
Promise 的基本使用
- Callback Hell
function loadImg(src, callback, fail) {
var img = document.createElement('img');
img.onload = function () {
callback(img);
}
img.onerror = function () {
fail();
}
img.src = src;
}
var src = 'https://www.imooc.com/courseimg/s/cover042_s.jpg';
loadImg(src, function (img) {
console.log(img.width);
}, function () {
console.log('failed');
})
- Promise 语法
function loadImg(src) {
const promise = new Promise(function (resolve, reject) {
var img = document.createElement('img');
img.onload = function () {
resolve(img);
}
img.onerror = function () {
reject();
}
img.src = src;
})
return promise;
};
var src = 'https://www.imooc.com/courseimg/s/cover042_s.jpg';
var result = loadImg(src);
result.then(function (img) {
console.log(img.width);
}, function () {
console.log('failed');
});
result.then(function (img) {
console.log(img.height);
});
【解答】
- new Promise 实例,而且要 return
- new Promise 时要传入函数,函数有 resolve reject 两个参数
- 成功时执行 resolve() 失败时执行 reject()
- then 监听结果
2-16 总结一下 ES6 其他常用功能
题目
总结一下 ES6 其他常用功能?
- let/const
- 多行字符串/模板变量
- 解构赋值
- 块级作用域
- 函数默认参数
- 箭头函数 (this)
知识点
- let/const
// JS
var i = 10;
i = 100;
// ES6
let i = 10;
i = 100; // 正确
const j = 20;
j = 200; // 报错
- 多行字符串/模板变量
// JS
var name = 'zhangsan', age = 20, html = '';
html += '';
html += ' ' + name + '
';
html += ' ' + age + '
';
html += '';
// ES6
const name = 'zhangsan', age = 20;
const html = `
${name}
${age}
`;
console.log(html);
- 解构赋值
// JS
var obj = { a: 100, b: 200 };
var a = obj.a;
var b = obj.b;
var arr = ['xxx', 'yyy', 'zzz'];
var x = arr[0];
// ES6
const obj = { a: 10, b: 20, c: 30 };
const { a, c } = obj;
console.log(a);
console.log(c);
const arr = ['xxx', 'yyy', 'zzz'];
const [x, y, z] = arr;
console.log(x);
console.log(y);
console.log(z);
- 块级作用域
// JS
var obj = { a: 100, b: 200 };
for (var item in obj) {
console.log(item);
}
console.log(item); // 'b'
// ES6
const obj = { a: 100, b: 200 };
for (let item in obj) {
console.log(item);
}
console.log(item); // undefined
- 函数默认参数
// JS
function fn(a, b) {
if (b == null) {
b = 0;
}
}
// ES6
function fn(a, b=0) {
}
- 箭头函数
// JS
var arr = [1, 2, 3];
arr.map(function (item) {
return item + 1;
});
// ES6
const arr = [1, 2, 3];
arr.map(item => item + 1);
arr.map((item, index) => {
console.log(index);
return item + 1;
});
function fn() {
console.log('real', this); // {a: 100}
var arr = [1, 2, 3];
// 普通 JS
arr.map(function (item) {
console.log('js', this); // window
return item + 1;
});
// 箭头函数
arr.map(item => {
console.log('es6', this); // {a: 100}
return item + 1;
});
}
fn.call({a: 100});
第3章 原型
3-1 开始
- 《前端 JS 面试技巧》已经讲解过原型的基础知识
- 高级面试题,光会原型基础还不够,还要实际应用
- zepto jquery 中如何用原型?
- 顺便也算是解读了 zepto 和 jquery 的部分源码
题目
原型如何实际应用?
- jquery 和 zepto 的简单使用
Document
jquery test 1
jquery test 2
jquery test 3
jquery test in div
- zepto 如何使用原型
(function (window) {
var zepto = {};
function Z(dom, selector) {
var i, len = dom ? dom.length : 0;
for (i = 0; i < len; i++) {
this[i] = dom[i];
}
this.length = len;
this.selector = selector || '';
}
zepto.Z = function (dom, selector) {
return new Z(dom, selector);
};
zepto.init = function (selector) {
var slice = Array.prototype.slice;
var dom = slice.call(document.querySelectorAll(selector));
return zepto.Z(dom, selector);
};
var $ = function (selector) {
return zepto.init(selector);
};
window.$ = $
$.fn = {
css: function (key, value) {
alert('css');
},
html: function (value) {
return '这是一个模拟的 html 函数';
}
}
Z.prototype = $.fn;
})(window);
- jquery 如何使用原型
(function (window) {
var jQuery = function (selector) {
return new jQuery.fn.init(selector)
};
jQuery.fn = {
css: function (key, value) {
alert('css');
},
html: function (value) {
return 'html';
}
};
var init = jQuery.fn.init = function (selector) {
var slice = Array.prototype.slice;
var dom = slice.call(document.querySelectorAll(selector));
var i, len = dom ? dom.length : 0;
for (i = 0; i < len; i++) {
this[i] = dom[i];
}
this.length = len;
this.selector = selector || '';
}
init.prototype = jQuery.fn;
window.$ = jQuery;
})(window);
原型如何满足扩展?
第4章 异步
- 《前端 JS 面试技巧》讲到异步的基础
- 高级面试会问到更多的内容
- 如 event-loop Promise Async/Await 等
题目
什么是单线程,和异步有什么关系?
- 单线程 - 只有一个线程,同一时间只能做一件事
// 循环运行期间,JS 执行和 DOM 渲染暂时卡顿
var i, sum = 0;
for (i = 0; i < 1000000000; i++) {
sum += i;
}
console.log(sum);
// alert 不处理, JS 执行和 DOM 渲染暂时卡顿
console.log(1);
alert('hello');
console.log(2);
- 原因 - 避免 DOM 渲染的冲突
浏览器需要渲染 DOM
JS 可以修改 DOM 结构
JS 执行的时候,浏览器 DOM 渲染会暂停
两段 JS 也不能同时执行(都修改 DOM 就冲突了)
webworker 支持多线程,但是不能访问 DOM
- 解决方案 - 异步
什么是 callback?异步完成之后要执行的函数
问题一:没按照书写方式执行,可读性查
问题二:callback 中不容易模块化
什么是 event-loop?
- 文字解释
事件轮询,JS 实现异步的具体解决方案
同步代码,直接执行
异步函数先放在 "异步队列" 中
待同步函数执行完毕,轮询执行 "异步队列" 的函数
如果只用 jquery 如何解决异步?- Deferred
- 是否用过 jQuery 的 Deferred
jQuery 1.5 的变化
使用 jQuery Deferred
初步引入 Promise 概念
- jQuery 1.5 的变化 - 1.5 之前
var ajax = $.ajax({
url: 'data.json',
success: function () {
console.log('success1');
console.log('success1');
console.log('success1');
},
error: function () {
console.log('error');
}
})
console.log(ajax); // 返回一个 XHR 对象
- jQuery 1.5 的变化 - 1.5 之后
var ajax = $.ajax('data.json');
ajax.done(function () {
console.log('success 1');
})
.fail(function () {
console.log('error');
})
.done(function () {
console.log('success 2');
})
console.log(ajax); // 返回一个 deferred 对象
// 很像 Promise 的写法
var ajax = $.ajax('data.json');
ajax.then(function () {
console.log('success 1');
}, function () {
console.log('error 1');
})
.then(function () {
console.log('success 2');
}, function () {
console.log('error 2');
})
- jQuery 1.5 的变化
无法改变 JS 异步和单线程的本质
只能从写法上杜绝 callback 这种形式
它是一种语法糖形式,但是解耦了代码
很好的体现:开放封闭原则 ( 对扩展开发,对修改封闭 )
- 使用 jQuery Deferred
var wait = function () {
var task = function () {
console.log('执行完成');
console.log('此处新需求......');
console.log('第一步');
console.log('第二步');
console.log('第三步');
};
setTimeout(task, 2000);
};
wait();
function waitHandle() {
var dtd = $.Deferred();
var wait = function (dtd) {
var task = function () {
console.log('执行完成');
dtd.resolve();
// dtd.reject()
}
setTimeout(task, 2000);
return dtd.promise(); // return dtd; => return dtd.promise();
}
return wait(dtd);
}
var w = waitHandle();
// w.then(function () {
// => 1.w 接收到的不再是一个 dtd 对象,而是一个 promise 对象
// => 2.只有 .then .done .fail 这种被动监听方法
// => 3.不再支持 .resolve .reject 这种主动方法的调用
$.when(w).then(function () {
console.log('ok 1');
}, function () {
console.log('err 1');
});
- jQuery 里引入 promise
总结,dtd 的 API 可分成两类,用意不同
第一类: dtd.resolve dtd.reject
第二类: dtd.then dtd.done dtd.fail
这两类应该分开,否则后果很严重!
可以在上面代码最后执行 dtd.reject() 试一下后果
Promise 的基本使用和原理?
- 基本语法回顾
function loadImg(src) {
const promise = new Promise(function (resolve, reject) {
var img = document.createElement('img');
img.onload = function () {
resolve(img);
}
img.onerror = function () {
reject();
}
img.src = src;
})
return promise;
};
var src = 'https://www.imooc.com/courseimg/s/cover042_s.jpg';
var result = loadImg(src);
result.then(function (img) {
console.log(img.width);
}, function () {
console.log('failed');
});
result.then(function (img) {
console.log(img.height);
});
- 异常捕获
// 捕获程序错误异常
// throw new Error('自定义错误');
result.then(function (img) {
console.log(img.width);
return img;
}).then(function (img) {
console.log(img.height);
}).catch(function (ex) {
// 统一捕获异常
console.log(ex);
})
// 捕获业务逻辑异常
// reject('图片加载失败');
// var src = 'https://cover042_sXXX.jpg';
result.then(function (img) {
console.log(img.width);
return img;
}).then(function (img) {
console.log(img.height);
}).catch(function (ex) {
// 统一捕获异常
console.log(ex);
})
- 多个串联
//业务需求;先加载一个,再加载另外一个
var src1 = 'https://www.imooc.com/courseimg/s/cover042_s.jpg';
var result1 = loadImg(src1);
var src2 = 'https://coding.imooc.com/static/module/class/content/img/190/section5-img.png';
var result2 = loadImg(src2);
// 链式操作
result1.then(function (img) {
console.log('第一个图片加载完成', img.width); // 240
return result2;
}).then(function (img) {
console.log('第二个图片加载完成', img.width); // 998
}).catch(function (ex) {
// 统一捕获异常
console.log(ex);
})
- Promise.all 和 Promise.race
// 全部完成才执行
Promise.all([result1, result2]).then(function (datas) {
console.log(datas[0]);
console.log(datas[1]);
});
// 只要有一个完成就执行
Promise.race([result1, result2]).then(function (data) {
console.log(data);
});
- Promise 标准
// 关于“标准”的闲谈
任何技术推广使用都需要一套标准来支撑
如 html js css http 等,无规矩不成方圆
任何不符合标准的东西,终将会被用户抛弃
不要挑战标准,不要自造标准
// Promise 标准 - 状态变化
三种状态:pending fulfilled rejected
初始状态是 pending
pending 变为 fulfilled ,或者 pending 变为 rejected
状态变化不可逆
// Promise 标准 - then
Promise 实例必须实现 then 这个方法
then() 必须可以接收两个函数作为参数
then() 返回的必须是一个 Promise 实例
介绍一下 async/await(和 Promise 的区别、联系)?
- then 只是将 callback 拆分了
var w = waitHandle();
w.then(function () {
console.log('ok 1');
}, function () {
console.log('err 1');
}).then(function () {
console.log('ok 2');
}, function () {
console.log('err 2');
});
- async/await 是最直接的同步写法
const load = async function () {
const result1 = await loadImg(src1);
console.log(result1);
const result2 = await loadImg(src2);
console.log(result2);
}
load();
- 语法
使用 await ,函数必须用 async 标识
await 后面跟的是一个 Promise 实例
需要 babel-polyfill
- 坑来了
// webpack 打包
1.首先,npm i babel-polyfill -D
2.运行报错,Uncaught ReferenceError: regeneratorRuntime is not defined
3.在 .babelrc 文件中添加:
"plugins": [
[
"transform-runtime",
{
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}
]
]
4.运行报错,ReferenceError: Unknown plugin "transform-runtime" specified
5.npm install babel-plugin-transform-runtime -D
6.运行再次报错,Cannot use import statement outside a module
7.
8.成功
// rollup 打包
1.npm i babel-polyfill -D
之前也报和 webpack 相同的错误,自己就好了,原因未知
- 小结
promise 是对异步回调的封装
async await 是使用 promise 时的一种扩展
完全是同步的写法,再也没有回调函数
但是:改变不了 JS 单线程、异步的本质
目前 JS 解决异步的方案有哪些?
- jQuery Deferred
- Promise
- Async/Await
- Generator