js

ES6入门

Posted by VickyWu on January 3, 2017

1 ES6阶段的准备

1.1 基础

浏览器暂时还不支持ES6所有功能,所以需要有工具把ES6 翻译到 ES5,我们用的是npm插件“babel”。

  1. 需要安装node,因为我们需要使用node包管理工具npm。

  2. 执行npm i -g gulp

  3. 创建项目目录,在项目目录下执行:

    1. npm init -f

    2. npm i gulp --save-dev

    3. npm i babel --save-dev

    4. npm i babel-preset-es2015 --save-dev

    5. npm install babel-preset-stage-3 --save

    6. npm install --save babel-polyfill

  4. 在项目目录下创建.babelrc文件,输入以下内容:
  5.     {
          "presets": ["es2015","stage-3"]
        }
    

    注意:windows下无法直接创建这样的文件(只有扩展名),你可以输入echo {"presets":["es2015"]} > .babelrc来创建一个.babelrc文件。当然,通常你的代码编辑器也允许你直接创建没有文件名只有扩展名的文件。

  6. 在项目目录下创建gulpfile.js文件,输入以下内容:
  7.     var gulp = require("gulp");
        var babel = require("gulp-babel");
    		
        gulp.task("default", function () {
          return gulp.src("src/**/*.js") 
            .pipe(babel())
            .pipe(gulp.dest("dist"));
        });
    
  8. npm_global文件夹解压到你自己的npm目录下。当你需要把ES6代码编译成ES5代码时,在项目文件夹下运行gulp就可以了。

1.2 自动编译

如果想要自动编译es6到es5的话。把gulpfile.js的内容改成这个:

	    var gulp = require("gulp");
	    var babel = require("gulp-babel");
	    gulp.task("default", function () {
	        return gulp.src("src/**/*.js")
	       .pipe(babel())
	       .pipe(gulp.dest("dist"));
     	});
	   gulp.task("es_compile",function(){
	    gulp.watch("src/**/*.js",['default'])
     	})

然后运行gulp es_compile

2 ES6常用语法

2.1 变量声明与作用域

let声明的变量局部作用域,允许有块级作用域,示例:

	for (let i = 0; i < 10; i++) {
	    console.log(i);
	}
	
	console.log('end', i) // 报错: app.js:7 Uncaught ReferenceError: i is not defined

let的优势: 1.创建了块级作用域 2.变量不会提升 3.不允许重复声明

const声明常量。

	const a = '1';
	a = 2  // 报错:SyntaxError: E:/heima_s1/ES6ClassProj/src/2.1/app.js: "a" is read-only

定义的变量为只读,定义赋值后,不能再赋值修改

2.2 解构赋值

一种能够快速给变量赋值的方式。

2.2.1 举例(数组解构):

var [a,b,c] = [1,2,3]

等价于:

var a = 1,
	b = 2,
	c = 3;

2.2.2 类似的还有(对象解构):

	var { data:{ name:n, pass:p } } = { data : { name:'zhangsan', pass:'123456' } }

等价于:

	var n = 'zhangsan',
		p = '123456'

2.2.3 还有(函数参数解构):

方法一:
    function test({show, type}){
	    console.log(show,type);
	}
	test({show:true,type:'text'});//true text
	test({index:0,show:true,type:'text'});//true text
	test({});//undefined undefined
方法二:
	function test({show = true, type = 'json'}){//含默认值
	    console.log(show,type);
	}
	test({show:true,type:'text'});//true text
	test({index:0,show:true,type:'text'});//true text
	test({});//true json

注意:解构赋值还允许有默认值。(不仅仅函数参数)

2.3 模板字符串

	var myName = 'zhangsan';
	var helloStr = `hello my name is ${myName}, I'm glad to meet you.`

用反引号” ` “包裹的字符串,允许你使用${ expr }在字符串内嵌入表达式的值。(expr的意思是表达式)。 另外,模板字符串允许换行,很适合在JavaScript里面拼写HTML。

2.4 数组操作

2.4.1 Array.from()

从一个类数组中获取真正的数组。

var arrayLike = {
  '0': 'a',
  '1': 'b',
  '2': 'c',
  'length': 2
};

var arr = Array.from(arrayLike);	
console.log(arr)

类似于从原型上拿slice方法。

2.4.2 find()和findIndex()

var array = [1,2,3,4,5];
console.log(array.find(x=>x<4)) // 返回1
console.log(array.findIndex(x=>x<4)) // 返回0

总之就是,找到第一个符合要求的。

2.4.3 includes()

[1,2,3].includes(2) // 返回true

数组是否包含指定项。

2.4.4 filter() *非es6

过滤

2.4.5 map() *非es6

映射

2.4.6 reduce() *非es6

累计

2.5 循环

对于数组、set和map(存储数据的其他结构)、arguments、DOM NodeList(querySelector出来的那个)、字符串等,可以使用for..of循环。

for(var value of [1,2,3]){
    console.log(value)
}

for(var value of 'hello world'){
    console.log(value)
}

2.6 数据结构

2.6.1 set

var set = new Set([1,1,2,3,4,5])

for(var i of set){
    console.log(i)
} // 输出1,2,3,4,5

总之,set不允许有重复值。

set具备的方法:add,delete,has,clear,values,forEach

你可以理解set为一个集合。

2.6.2 map

var map = new Map();

map.set('a', 1);
map.set('b', 2);

for (var item of map) {
    console.log(item);
}

键值对存储。比Obj方便的地方是,键不一定非得是字符串了。

map这个单词在这里的意思是映射。键值对之间存在着映射关系。

map所具备的方法,set,get,has(key),delete(key),keys,values,entries,forEach

注意,因为map的每一项都有自己的key和value,所以遍历时还可以这么写,更加方便。(利用了解构赋值)

var map = new Map();

map.set('a', 1);
map.set('b', 2);

for (var [key,value] of map) {
    console.log(key,value);
}

2.7 箭头函数

var func = () => { console.log('hello world') }

等价于

var func = function(){ console.log('hello world') }

另外,当大括号里的语句只有一行时,可以省略大括号:

var func = () =>  console.log('hello world') 

2.8 generator 函数

用法

function* helloWorld(){
	var hello = yield 'hello';
	var world = yield 'world';
	console.log('')
	return'end';
}

var hw = helloWorld();

var result = hw.next();
while(!result.done){
    console.log(result.value);
    result = hw.next('hi')
}
console.log(result.value);

// 输出分别为 hello, world, hi hi 和 end

2.8.2 这玩意儿的用途?

假设,我们有这样的一个需求。

访问/usertype.json向服务器询问用户类型

=> 如果类型是A,则访问/usera.json获取数据,把数据放到页面上 => 如果类型是B,则访问/userb.json获取数据,把数据放到页面上

function* getData(actionsObj) {
    var userType = yield actionsObj.step1();
    var data ;
    if (userType == 'a') {
        // 访问A
         data = yield actionsObj.step2a();
    } else {
        // 访问B
         data = yield actionsObj.step2b();
    }
    console.log(`user's name is:`,data);
    return 'end';
}


var obj = {
    init: function () {
        var gd = getData(this);
        this.gd = gd;
        this.gd.next(this);
    },
    step1: function () {
        var _this = this;
        $.get('type.json', function (data) {
            _this.gd.next(data.type)
        })
    },
    step2a: function () {
        var _this = this;
        $.get('usera.json', function (data) {
            _this.gd.next(data.name)
        })
    },
    step2b: function () {
        var _this = this;
        $.get('userb.json', function (data) {
            _this.gd.next(data.name)
        })
    }
};

obj.init();

2.9 promise

var promise = new Promise(function (resolve, reject) {
    $.ajax({
        url: 'dataa1.json',
        datatype: 'json',
        type: 'get',
        success: resolve,
        error: reject
    })

})

promise
    .then(function (data) {
        console.log(data);
    })
    .catch(function (error) {
        console.log(error);
    }) 

总之,又是一个管理异步的。

还是原来的问题,如何分步走呢?下面代码:

var promise = new Promise(function (resolve, reject) {
    $.ajax({
        url: 'type.json',
        datatype: 'json',
        type: 'get',
        success: resolve,
        error: reject
    })

})

promise
    .then(function (data) {
        console.log('step1',data);
        return new Promise(function (resolve, reject) {
            console.log(resolve,reject);
            $.ajax({
                url: 'usera.json',
                datatype: 'json',
                type: 'get',
                success: resolve,
                error: reject
            })
        })
    })
    .then(function(data){
        console.log('step2',data)
    })
    .catch(function (error) {
        console.log(error);
    }) 

原来promise允许返回promise,于是下一步就可以接着用了。

除了分步走,promise还能做“所有人都搞定了,我再走”:

var promise = Promise.all([promise1,promise2,promise3])
promise.then(function(){ ... })

还有一个与之相反的“有一个搞定了,我就走”

var promise = Promise.race([promise1,promise2,promise3])
promise.then(function(){ ... })

还有一个“无论搞定没搞定,所有人都回信了,我就走”:

var promise = ...
promise
	.then(function(){ ... })
	.finally(fucntion(){ ... })

##2.10 async函数

其实前面两个解决回调问题的方法都很麻烦是吧?

实际上还有另外一种策略,当然,这个是es7提供的

async function demo() {
    var type = await getType();
    console.log(type);
    var usera = await getUserA();
    console.log(usera);
}

function getType() {
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: 'type.json',
            datatype: 'json',
            type: 'get',
            success: resolve,
            error: reject
        })
    })
}

function getUserA() {
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: 'usera.json',
            datatype: 'json',
            type: 'get',
            success: resolve,
            error: reject
        })
    })
}

demo();

最后放上大牛阮一封ES6文档