- 开发环境已普及
- 浏览器环境支持不好(需要开发环境编译)
- 开发环境如何使用+重点语法的掌握
问题:
- 模块化,开发环境如何打包
- Class与普通构造函数
- Promise
- 总结ES6常用功能
模块化与打包
-
export与import语法
/* util1.js*/ export default { a: 1 } /* util2.js */ export function fun1() {} export function fun2() {} /* index.js */ import util1 from './util1' import {fun1, fun2} from 'util2'
-
模块化
- 开发环境 - babel语法解析,将ES6语法解析成浏览器可识别的低层次语法
-
node环境安装
-
创建项目工程文件:es-test
-
在项目根目录下,npm init
-
npm install —save-dev babel-core babel-preset-env babel-preset-latest
-
在项目根目录下,创建.babelrc文件,这是babel的配置文件
// .babelrc { "presets": ["env", "latest"], "plugins": [] }
-
npm install —global babel-cli
-
babel —version,可以查看当前版本号
-
创建./src/index.js
. └── src └── index.js
// index.js [1, 2, 3].map(item => item + 1)
-
运行 babel ./src/index.js
// 控制台打印 [1, 2, 3].map(function (item) { return item + 1; });
-
- 开发环境 - webpack处理模块化
-
npm install webpack babel-loader —save-dev
-
配置 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" }] } }
-
配置 package.json 中的 scripts
"scripts": { "start": "webpack", "test": "echo \"Error: no test specified\" && exit 1" },
-
运行 npm start
-
- 开发环境 - rollup
- npm init
- npm i —save-dev rollup rollup-plugin-node-resolve rollup-plugin-babel babel-plugin-external-helpers babel-preset-latest
- 配置 .babelrc
- 配置 rollup.config.js
- Webpack、rollup比较
- rollup功能单一,webpack功能强大
- 参考设计原则和《Linux/Unix设计思想》
- 工具尽量功能单一,可集成,可扩展
- 开发环境 - babel语法解析,将ES6语法解析成浏览器可识别的低层次语法
-
总结
- 语法: import export(注意有无 default)
- 环境: babel 编译 ES6 语法,模块化可用webpack 和 rollup
- 扩展:说一下自己对模块化标准统一的期望
-
时间轴
- 没有模块化
- AMD 成为标准,require.js (也有CMD)
- 前端打包工具,是nodejs模块化可以被使用
- ES6出现,想统一现在的所有模块化标准
- nodejs积极支持,浏览器尚未统一
- 可以自造lib,但不能自造标准
Babel7 的配置与使用
Babel是将ES6语法转换成浏览器可识别的向后兼容版本的JS代码。
从低版本到babel7,有几项变化:
- 不再支持不在维护中的 Node 版本:0.10、0.12、4、5;
- 使用 @babel 命名空间,因此 babel-core 就变成了 @babel/core;
- 移除(并停止发布)任何年度预设(preset-es2015 等),@babel/preset-env 取代了对这些内容的需求 ;
- 移除“Stage” 预设(@babel/preset-stage-0 等),同时移除了 @babel/polyfill 中的提议;
- 重命名了某些包:任何 TC39 提议插件现在都是 -proposal 而不是 -transform,所以 @babel/plugin-transform-class-properties 变成了 @babel/plugin-proposal-class-properties;
- 针对某些面向用户的包(例如 babel-loader、@babel/cli 等)在 @babel/core 中引入 peerDependency;
-
Babel-upgrade
babel-upgrade 是一个用于自动升级的新工具,具体可见https://github.com/babel/babel-upgrade
建议直接在git仓库上运行
npx babel-upgrade
,或者使用npm i babel-upgrade -g
进行全局安装。若是想修改文件,可是使用参数--write
和--install
npx babel-upgrade --write --install
-
安装配置
npm install --save-dev @babel/core @babel/cli @babel/preset-env npm install --save @babel/polyfill // 注意 --save 选项而不是 --save-dev,因为这是一个需要在源代码之前运行的 polyfill。
配置Babel,你可以使用
.babelrc
文件方式,同时Babel 7 引入了 babel.config.js,babel.config.js 的配置解析方式与.babelrc 不同。它始终会解析该文件中的配置,而不会从每个文件向上查找,直到找到配置为止。这样就可以利用 overrides 特性。
-
.babelrc
{ "presets": [ ["@babel/env", { "targets": { "edge": "17", "firefox": "60", "chrome": "67", "safari": "11.1" }, "useBuiltIns": "usage", "debug": true // 可以看到打包的文件。 } ] ], "plugins": [] }
-
babel.config.js
const presets = [ ["@babel/env", { targets: { edge: "17", firefox: "60", chrome: "67", safari: "11.1" }, useBuiltIns: "usage" }] ]; var env = process.env.NODE_ENV; module.exports = { presets, plugins: [ env === "production" && "babel-plugin-that-is-cool" ].filter(Boolean) };
使用
overrides
进行选择性配置module.exports = { presets: [ // defeault config... ], overrides: [{ test: ["./node_modules"], presets: [ // config for node_modules ], }, { test: ["./tests"], presets: [ // config for tests ], }] };
有些应用程序需要针对测试、客户端代码和服务器代码使用不同的编译配置选项,通过这种方式就不需要在每个文件夹下创建.babelrc 文件了。
我们使用的是
env
preset,其中有一个"useBuiltIns"
选项,当设置为"usage"
时,实际上将应用上面提到的最后一个优化,只包括你需要的 polyfill。例如
Promise.resolve().finally()
会变成这个require("core-js/modules/es.promise.finally"); Promise.resolve().finally();
如果我们没有将env
preset 的"useBuiltIns"
选项的设置为"usage"
,就必须在其他代码之前 require 一次完整的 polyfill。 -
运行
./node_modules/.bin/babel src --out-dir lib
将所有代码从src
目录编译到lib
我们使用
@babel/cli
从终端运行 Babel,@babel/polyfill
来实现所有新的 JavaScript 功能,useBuiltIns:entry 会根据target环境加载polyfill,需要手动import polyfill,不能多次引入。@babel/preset-env会将把@babel/polyfill根据实际需求打散,只留下必须的。做的只是打散。仅引入有浏览器不支持的polyfill。这样也会提高一些性能,减少编译后的polyfill文件大小。env
preset 只包含我们使用的功能的转换,实现我们的目标浏览器中缺少的功能。 -
Class 和普通构造函数的区别
-
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()) // 3 typeof MathHandle // function MathHandle/prototype.constructor === MathHandle // true m.__proto__ === MathHandle.prototype // true
-
Class 基本语法
class Ad extends Rect.Component { constructor(props) { super(props) this.state = { data: [] } } componentDidMount() {} render() { return ( <div>hello world</div> ) } }
-
语法糖
class MathHandle { // ... } typeof MathHandle // function MathHandle/prototype.constructor === MathHandle // true m.__proto__ === MathHandle.prototype // true
-
继承
// 动物 function Animal() { this.eat = function() { console.log('animal eat') } } // 狗 function Dog() { this.dark = function() { console.log('dog dark') } } Dog.prototype = new Animal() var d = new Dog()
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`) } } var dog = new Dog('hashiqi') dog.say() dog.eat()
-
总结
- class 在语法上更加贴合面向对象的写法
- class 实现继承更加易读、易理解
- 更易于写Java等后端语言的使用
- 本质还是语法糖,使用 prototype
Promise
function loadImg(src, callback, fail) {
var img = document.createElement('img')
img.onload = function () {
callback(img)
}
img.onerror = function () {
fail()
}
img.src = src
}
var src= 'http://www.imooc.com/static/img/index/logo_new.png'
loadImg(src, function (img) {
console.log(img.width)
}, function () {
console.log('failed')
})
function loadImg(src) {
return new Promise(function (resolve, reject) {
var img = document.createElement('img')
img.onload = function () {
resolve(img)
}
img.onerror = function () {
reject()
}
img.src= src
})
}
var src = 'http://www.imooc.com/static/img/index/logo_new.png'
var result = loadImg(src)
result.then(function (img) {
console.log(img.width)
}, function () {
console.log('failed')
})
result.then(function (img) {
console.log(img.height)
})
其他常用功能
-
let/const
// js var i = 10 i = 100 // es6 let i = 10 i = 100 const j = 20 j = 200 // 报错
-
多行字符串/模板变量
// js var name = 'an' var html + = '<div>' html += name html += '</div>' //es6 var name = 'an' const html = `<div>${name}</div>`
-
解构赋值
//js var obj = {a:1, b: 2} obj.a var arr = [1, 2, 3] arr[0] //es6 const obj = {a:1, b: 2} const {a, b} = obj a const arr = [1, 2, 3] const [a, b, c] = arr x
-
块级作用域
//js var obj = {a: 1, b: 2} for (var item in obj) { console.log(item) } console.log(item) // output: b // es6 const obj = {a: 1, b: 2} for (let item in obj) { console.log(item) } console.log(item) // output: undefined
-
函数默认参数
// js function(a, b) { if (b == null) b = 0 } // es6 function(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 fun() { console.log(this) // output: {a: 100} var arr = [1, 2, 3] // js arr.map(function(item) { console.log(this) // output: window return item + 1 }) // 箭头函数:对普通JS的补充 arr.map(item =>{ console.log(this) // output: {a: 100} return item + 1 }) } fun.call({a: 100})