es6 学习笔记(一)
环境搭建和简单实践
怎么es6还要环境搭建呢?我用的还是javascript吗?然而不是这么一回事。
es6在语法上有很多的变化,算是脱胎换骨了,但是因为浏览器还没有完全支持es6的新语法,所以使用es6开发,就应该先将其转化为es5,那么就需要工具来完成,
babel
Babel是一个编译器,负责将源代码转换成指定的语法的目标代码,可以使之很好的在运行环境中执行我们的代码。
安装babel的命令行工具:
//一般要先在当前项目生成一个package.json;然后将babel-cli安装在本地 ,它只是一个开发依赖。另外不同的项目依赖库的版本可能都不同,全局的babel-cli库也不能保证兼容各个项目中其他依赖库的版本。
$ npm install -D babel-cli;
安装转码规则包,Babel支持很多语法的转码,可以选择集成的。
babel-preset-env 是一个新的 preset,可以根据配置的目标运行环境(environment)自动启用需要的 babel 插件,babel-preset-env 的工作方式类似 babel-preset-latest,唯一不同的就是 babel-preset-env 会根据配置的 env 只编译那些还不支持的特性。
$ npm install -D babel-preset-env
然后编译,
//编译某个具体的js文件 $ babel index.js --out-file index-compile.js //编译目录中所有的js文件并另存到指定目录 $ babel src --out-dir lib / $ babel src -d lib
每次都这样做,太繁琐了?试用一下这条命令。在package.json文件中的script中添加:
"build": "babel src -d lib"
它可以实现简单的编译的功能,不过这不是最好的解决方案,
因为Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API ,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转码
为了能够完全转换es6的内容,需要安装babel-polyfill插件
1.先引入webpack,这里只是因为babel-polyfill可以在Node/Browserify/webpack中使用
//全局安装,在配置完成后,可以直接通过webpack运行, $ npm install -g webpack //一般会装在本地项目中,就不能直接使用webpack需要找node_module中的webpack的位置。 $ npm install -D webpack
2.安装babel-polyfill插件,babel-cli,babel-preset-env
$ npm install -save-dev babel-polyfill babel-cli babel-preset-env
3.在需要的文件中引入babel-polyfill:
import "babel-polyfill";
//node.js中引入:require('babel-polyfill');
4.配置webpack.config.js文件,将['babel-polyfill', './src/index.js'] 写到entry属性中。如下
const path = require('path'); module.exports = { entry: ['babel-polyfill', './src/index.js'], module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" } ] }, output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } };
5.配置.babelrc文件
{ "persets": ["env"]; }
6.启动webpack
$ webpack
promise
promise是什么?(来自sf.gg的promise百科)
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了 Promise 对象。
所谓 Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
promise方法:
1.构造函数
Promise( function(resolve, reject) { } );
2.实例,构造函数用于生成Promise对象
let promise = new Promise(function(resolve, reject) { });
3.基本用法
Promise链式调用的原因?
因为Promise.prototype.then方法和Promise.prototype.catch方法都返回Promise对象。所以可以链式调用
Promise对象的其他用法。
1.Promise.all()
将多个Promise实例,包装成一个新的Promise实例
let promise = Promise.all([promiseOne,promiseTwo]);
而且,只有当promiseOne 和 promiseTwo 都成功的时候,promise才会成功
2.Promise.race()
该方法同样是将多个Promise实例,包装成一个新的Promise实例。只不过在这种情况下,只要其中一个被成功调用,promise 就会被成功调用。
继续研究参考:https://segmentfault.com/a/1190000011742644
axios
基于http客户端的promise,面向浏览器和nodejs
安装:
使用 npm:
$ npm install axios
使用 bower:
$ bower install axios
引入axios.js
在bowe_components中引入axios.js
axios请求
axios.get('http://h6.duchengjiu.top/shop/api_goods.php') .then(response => { console.log(response.data); });
generator & yield
1.生成器函数(Generator Function)
//声明式 function* gene() { //... }
//定义式 const gene = function*() { //... }
2.yield
yield的作用与return相似,但是yield不会退出函数体,而是切出当前函数的运行时(此处为一个类协程,Semi-coroutine),并与此同时可以讲一个值(可以是任何类型)带到主线程中。
3.使用方法:
构建生成器函数
function* genFn() { let a = 2 yield a while (true) { yield a = a / (2 * a + 1) } }
执行generator函数
generator函数不能直接作为函数来使用,执行generator函数会返回一个生成器对象,将用于运行生成器内容和接受其中的值。
const gen = genFn()
运行生成器内容
for (const a of gen) { if (a < 1/100) break console.log(a) }
迭代器
1.for-in
都知道for-in循环用来遍历对象,但是细心的你也会发现,for-in无法控制遍历的顺序,它永远都是从第一个到最后一个。
2.for-of
for-of是es6的新语法,它用来配合迭代器,迭代对象,我们可以控制迭代顺序,
3.Symbol.iterator
对象被迭代的条件是它需要有一个Symbol.iterator属性,他是一个独一无二的属性,暂不详细介绍。
4.迭代器长啥样?
iterator[Symbol.iterator] = function () { return { next: function () {} } } //iterator[Symbol.iterator]() 它会返回一个类似于{next: function() {}}对象,原型是Array Iterator let iterator = iterator[Symbol.iterator](); //iterator.next(),会返回一个类似于{value: …, done: [true/false]}的对象, iterator.next();
那么next()内部大概是这样的:
table[Symbol.iterator] = function () { var keys = Object.keys(this).sort(); var index = 0; return { next: function () { return { value: keys[index], done: index++ >= keys.length }; } } }
针对对象,自己写一个迭代器
{ let obj={ start:[1,3,2], end:[7,9,8], [Symbol.iterator](){ let self=this; let index=0; let arr=self.start.concat(self.end); let len=arr.length; return { next(){ if(index<len){ return { value:arr[index++], done:false } } else { return { value:arr[index++], done:true } } } } } // 遍历迭代器 let iterator = obj[Symbol.iterator](); console.log(iterator); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); }
5.惰性执行:
如果next()函数永远不被调用的话,我们就浪费了性能。所以让我们来优化它:
table[Symbol.iterator] = function () { var _this = this; var keys = null; var index = 0; return { next: function () { if (keys === null) { keys = Object.keys(_this).sort(); } return { value: keys[index], done: index++ >= keys.length }; } } }
6.内置迭代器
String,Array,TypedArray,Map和Set都是内置迭代器,因为它们的原型中都有一个Symbol.iterator方法
7.Generator函数
function* iterator(arr) { for(let item of arr) { yield item; } } let iter = iterator([1,2,3,5,6,7]); for(let k of iter) { console.log(k); }
这两种都可以用来迭代,iter是一个迭代器,像上面我们分析的那样,
它内部会返回 {next: function() { } }, for-of也是同样。
//iter.next();
//for(let k of iter) {}
8.iterables
iterable是一个概念,表示有Symbol.iterator属性的object,
这个属性指向一个generator函数,调用这个函数,会返回一个关于这个对象的iterator,
在ES6中所有的集合类对象(array, set, maps)和字符串都是iterable,并且有自己默认的iterator,
所以在使用for-of迭代的时候,每次都是利用了对象上的iterator,调用next(),
9.向迭代器中传递参数
function* createIterator() { let first = yield 1; let second = yield first + 2; yield second + 3; } let i= createItreator() i.next() // {value:1 done: false} i.next(5) // {value: 7 done: false} i.next(3) // {value: 6 done: false}e}
10.应用实例
function run(taskDef) { let task = taskDef(); let value = task.next() function step() { if (!value.done) { value = task.next(value.value) step() } } step() } run(function*(){ let first = yield 1; let second = yield first + 3; yield second + 4; })