Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES6 新手学习记录档 #8

Open
qixMan opened this issue Mar 12, 2016 · 0 comments
Open

ES6 新手学习记录档 #8

qixMan opened this issue Mar 12, 2016 · 0 comments

Comments

@qixMan
Copy link
Owner

qixMan commented Mar 12, 2016

ES6 新手学习记录档

[!TOC]

let const

let

在ES5中,通过var声明的变量,作用域是通过function划分的,在function内声明的变量,在函数外无法使用,但是在块(例如if、for等)之外,仍然是有效的。

if(true) { var a = 1 }
console.log(a)//1

但是对于ES6中的let、const两个关键词来说,区别于原来的var,形成block scope(块级作用域)。块内声明的变量,块外无效

if(true) { let a = 1 }
console.log(a)//ReferenceError

ES5时代函数级作用域引发的一个问题场景,就是在循环赋值的时候。

var funcs = []
for(var i=0;i<10;i++){
    funcs.push(function(){
        console.log(i)
    })
}

funcs.forEach(function(func){
    func()
})
//运行结果是10个10,而不是预期的0,1,2,3...
开发人员通常用js闭包的特性来搞定这个问题
var funcs = []
for(var i=0;i<10;i++){
    (function(idx){
        funcs.push(function(){
            console.log(idx)
        })
    })(i)
}

funcs.forEach(function(func){
    func()
})
//运行结果为0,1,2,3,4....

ES6中增加了块级作用域的概念,就可以使用let取代var,便不需多写闭包这种hack了。
值得一提的是,let不存在变量提升,但是它有个暂时性死区的概念。

console.log(a)//undefined
console.log(b)//报错,没有提升
var a = 1
let b = 1

所谓暂时性死区,就是一个区域,从变量所在的作用域开头,到变量使用let声明之间的区域,在这个区域内,对这个变量的一切操作都会报错。

const

const是个常量的概念,一些配置信息或者不变更的量都可以用const来定义,防止被胡乱篡改。

const a = 1
a = 2 //报错

这里需要注意的是,const声明的变量,如果是引用类型,那么这个变量的内容是可以改变的。const能保证的,只是指针的不变。

const a = {}
a = {}//报错

a.name = "xiaoming"//没问题
Array Function

箭头函数,这个语法的出现,让函数的写法更加简单了,尤其是写匿名函数的时候,例如:

//es5
let arr = [1,2,3].map(function(x){
    return x+1
})

//es6
let arr2 = [1,2,3].map((x)=>(x+1))
//小括号可以不加,但是为了防止挖坑,一般加上。
//函数体内容较多的时候,用{}

值得注意的是箭头函数中的this,是定义时所在的对象,而不是使用时所在的对象。
所以可以告别var self = this这种hack了。

var bob = {
    _name: "Bob",
    _friends: [],
    printFriends() {
        this._friends.forEach(f => consol.log(this._name + " knows " + f));
    }
}

Class

ES6 class 与 ES5 prototype 两种思路实现oop的对比

这是一个语法糖,开发人员写oop‘可能’更便捷了,而且代码可读性有所提高,更重要的是,这个改变很可能是对将来一些新功能的拓展做准备。

在es5里,我们实现一个类,依靠的是function以及prototype这两个东西,function可以配合关键词new创建实例,prototype可以让对象继承其他对象。

//es5
function Person(name) {
    this.name = name;
    Person.count++
}
//一些其他方法
Person.prototype.sayNotGood = function(){
    console.log('hey,' + this.name+",you are " + Person.getCount() +" I've created,heyheyhey")
}

//静态方法
Person.getCount = function(){
    return Person.count + "th"
}

//静态属性
Person.count = 0

let xiaoming = new Person('xiaoming')
xiaoming.sayNotGood()//hey,xiaoming,you are 1th I"ve created,heyheyhey

而在ES6中,引进了class关键词,创建类变得方便,对有java等oop语言开发基础的同志来说,尤其如此

   //es6
   class Person{
       //构造函数
       constructor(name){
           this.name = name
           Person.count++
       }

       //其他方法
       sayNotGood(){
           console.log(`hey,${this.name},you are ${Person.getCount()} I ve created,heyheyhey`)
       }

       //静态方法
       static getCount(){
           return Person.count + "th"
       }
   }

   //静态属性这个语法在es7才能实现,目前state-0
   Person.count = 0

   let xiaoming = new Person('xiaoming')
xiaoming.sayNotGood()//hey,xiaoming,you are 1th I've created,heyheyhey

也说过了,class只是一个语法糖,它本质上,还是一个function

typeof Person//function

但是还是有一些性质上的差别,比如class与function没有提升

let p = new Person()
class Person{}
//这得报错

关于继承(没有填的坑)

Template string

模板字符串,有了这个新特性,+号拼接字符串的时代就过去了,变成了往字符串里面插变量。

let name = "xiaoming"
`hey,${name}` // "hey,xiaoming"
parameter

default parameter

默认参数在别的编程语言中比较常见了,在没有对参数赋值的时候,使用默认值。在es5中,常用||也就是‘或’来实现相关逻辑。

//es5
function foo(bar){
    var a = bar ||'baz'
    console.log(a)
}

foo()//'baz'
foo('shit')//'shit'

在es6里,这个逻辑可由默认参数来完成

//es6
let foo = (a='baz')=>{
       console.log(a)
   }

foo()//'baz'
foo('shit')//'shit'
rest parameter

这个语法允许把一坨参数作为数组调用。
在es5中,由于arguments是arraylike类型,是个object,因此无法使用forEach、map等好用的array method。以往的处理方式是hack一下,利用[].slice.call(arguments,0)切割一下。

function addSome(){
       var paras,sum
       paras = [].slice.call(arguments,0)
       sum = paras.reduce(function(sum,next){
           return sum + next
       })
       console.log(sum)
   }

   addSome(1,2,3)//6

这个语法的出现,可以彻底取消这个hack,直接操作原生数组

let addSome = (...nums)=>(nums.reduce((sum,next)=>(sum+next)))
addSome(1,2,3)//6

顺便说一点,ES6中对Array也添加了一些新的好用的api,其中Array.from也是一个能将arrylike转化成原生array的利器

Array.from(arguments)
//等价于
[].slice.call(arguments,0)

反过来,形参很多,实参出入一个数组,也是可以自动解析的,关键语法在于...的使用

let add3num = (x,y,z) => (x+y+z) 
let arr = [1,2,3]
console.log(add3num(...arr))//6

For…of

for…of跟for…in不同很多,都说for-in遍历的时候可能不按顺序来,因此不适合遍历数组,最好用来遍历属性,不过我写了一些test倒是没实现…

二者最根本的区别,不是别的:for-of遍历值,for-in遍历索引

let arr = [1,2,3]
   for(let i in arr){
       console.log(i)//0,1,2
   }

   for(let i of arr){
       console.log(i)//1,2,3
   }

for-of本质上遍历的不是一个数组,而是数组自动调用生成的迭代器iterator,因此凡是拥有迭代属性的东西,for-of都能遍历,比如generator,比如iterator

//for-of搞generator
function *fibonacci(stop){
    let [a,b] = [0,1]
    for(let i=1; i<=stop; i++){
        [a,b] = [b,a+b]
        yield a
    }
}

for(let i of fibonacci(5)){
    console.log(i)//1,1,2,3,5
}

//for-of搞iterator
let arr = [1,2,3]
    iter = arr[Symbol.iterator]()
for(let i of iter){
    console.log(i)//1,2,3
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant