学习推荐:http://johnhax.net/2014/es6-js-future/
教程推荐【必读】:http://es6.ruanyifeng.com/#docs/destructuring
3.for...in可用于遍历json对象,但是for循环不行!
不仅是在ES6,应该是在更早之前,就已经出现了const与let,但是我一直不了解而已,我只知道const是不可更改的而且必须被初始化!let一般用于局部变量,长用于闭包循环。而js在预编译的时候会将var声明的变量提到全局作用域的顶部,如果声明的是全局变量则会提到最前面,如果是局部变量则提到局部作用域的顶部。使用var声明的变量,如果没有赋值就直接使用则会输出undefined。
为了解决这个问题,const与let出现了,这二者只在所声明的块级作用域有效,在代码块中使用const和let声明的变量会陷入暂时性死区直到该变量的声明被销毁。
暂时性死区:在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
上面代码中,在let命令声明变量tmp之前,都属于变量tmp的“死区”。
1.使用var:
如果输出是一个为赋值的变量,结果是常见的undefined。
结果和const类似,因为它俩都是在块级区域内声明,出了块级区域就不再被识别,会报错未定义的变量。
如果const声明的变量提前了,那按理说应该输出20或undefined,但结果却是未定义,简介说明了const声明的变量也不会提前!
使用let声明的变量可以重新赋值,但是不能在同一作用域内重新声明
使用const声明的变量必须赋值初始化,但是不能在同一作用域类重新声明也无法重新赋值.
上面的函数有两个代码块,都声明了变量n,运行后输出 5。这表示外层代码块不受内层代码块的影响。如果两次都使用var定义变量n,最后输出的值才是 10。
上面代码使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量。
块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。
顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。
上面代码中,顶层对象的属性赋值与全局变量的赋值,是同一件事。
顶层对象的属性与全局变量挂钩,被认为是 JavaScript 语言最大的设计败笔之一。这样的设计带来了几个很大的问题,首先是没法在编译时就报出变量未声明的错误,只有运行时才能知道(因为全局变量可能是顶层对象的属性创造的,而属性的创造是动态的);其次,程序员很容易不知不觉地就创建了全局变量(比如打字出错);最后,顶层对象的属性是到处可以读写的,这非常不利于模块化编程。另一方面,window对象有实体含义,指的是浏览器的窗口对象,顶层对象是一个有实体含义的对象,也是不合适的。
ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
上面代码中,全局变量a由var命令声明,所以它是顶层对象的属性;全局变量b由let命令声明,所以它不是顶层对象的属性,返回undefined。
在ES6之前,将字符串连接到一起的方法是+或者concat()方法,如
模板字面量用倒引号 ( `` )(而不是单引号 ( '' ) 或双引号( "" ))表示,可以包含用 ${expression} 表示的占位符【倒引号:tab上面的一个键】
在ES6中,可以使用解构从数组和对象提取值并赋值给独特的变量
总结:发现了一个问题,这个console.log竟然能直接访问对象里的属性,而不需要对象去指向。这是解构中需要特别注意的地方。
输出:
使用和所分配的变量名称相同的名称初始化对象时如果属性名称和所分配的变量名称一样,那么就可以从对象属性中删掉这些重复的变量名称。如果一样就删掉,如果不一样,你还是要像原来那样写。
总结:在简介语法里,给对象赋值时方便了。在ES6中,匿名函数【仅限于对象中!】不在需要function关键字修饰。
for...of循环是最新添加到 JavaScript 循环系列中的循环。它结合了其兄弟循环形式 for 循环和 for...in 循环的优势,可以循环任何可迭代(也就是遵守可迭代协议)类型的数据。默认情况下,包含以下数据类型:String、Array、Map 和 Set,注意不包含 Object 数据类型(即 {})。默认情况下,对象不可迭代。
虽然 for 循环在循环数组时的确具有优势,但是某些数据结构不是数组,因此并非始终适合使用 for 循环。
特点:需要跟踪器 | 无法退出 | 只能用于循环数组 | 给数组原型添加其他属性或方法不影响
for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。如果是在统一作用域内同时声明两个相同名称和类型的变量i,编译是通不过的!
当你需要向数组中添加额外的方法(或另一个对象)时,for...in 循环会带来很大的麻烦。因为 for...in 循环访问所有可枚举的属性,意味着如果向数组的原型中添加任何其他属性,这些属性也会出现在循环中。
确实!我在Array原型中添加的一个方法,遍历时竟然也打印了这个方法名!就像上面说的那样!
特点:需要跟踪器 | 无法退出 | 也可用来遍历json对象 | 不能给数组原型添加其他属性或方法
3.for...in可用于遍历json对象,但是for循环不行!
因为json对象不存在length和size属性,也就是说无法获取json对象中属性/方法的个数。但是却可以使用inarr[i]的方式去访问json对象中属性!
我从来没用过foreach,也很少见过有人使用过foreach!forEach() 实际上是数组方法,因此只能用在数组中。也无法停止或退出 forEach 循环。如果希望你的循环中出现这种行为,则需要使用基本的 for 循环。仔细对比几种循环,只有foreach可以将数组写在前面啊!
特点:跟踪器可要可不要 | 只能用于循环数组 | 无法退出 | 给数组原型添加其他属性或方法不影响
for...of 循环的编写方式和 for...in 循环的基本一样,只是将 in 替换为 of,可以忽略索引。
对比可以看出:for...in与for...of都是只能绑定一个参数,for...in绑定的时index,而for...of绑定的时value。而且for...of不在需要跟踪器!
for...of 循环还具有其他优势,解决了 for 和 for...in 循环的不足之处。你可以随时停止或退出 for...of 循环。
特点:不需要跟踪器 | 只能用于循环数组 | 及时停及时止 | 给数组原型添加其他属性或方法不影响
展开运算符(用三个连续的点 (...) 表示)是 ES6 中的新概念,使你能够将字面量对象展开为多个元素。
如果你需要结合多个数组,在有展开运算符之前,必须使用 Array的 concat() 方法。当然还有之前学的call函数和apply函数。
使用展开运算符将数组展开为多个元素, 使用剩余参数可以将多个元素绑定到一个数组中。
剩余参数也用三个连续的点 ( ... ) 表示,使你能够将不定数量的元素表示为数组。
对于参数不固定的函数,ES6之前是使用参数对象(arguments)处理:
对比发现其实就相当与给其提供了一个参数入口而已,类似java那样,也有一种写法可以表示多个参数。ES6更贴近于其他语言吧。
普通函数可以是函数声明或者函数表达式, 但是箭头函数始终都是表达式, 全程是箭头函数表达式, 因此仅在表达式有效时才能使用,包括:
也就是说greet为函数名称,name为其参数,最后为其return的结果。
如果函数的参数只有一个,不需要使用()包起来,但是一个没有或者多个, 则必须需要将参数列表放在圆括号内:
但是如果箭头函数的主体内需要多行代码, 则需要使用常规主体语法:
函数使用call/apply被调用,this的值指向指定的obj2,因为call()第一个参数明确设置this的指向
此处this指向的是全局对象,但是在严格模式下,指向undefined
对于普通函数, this的值基于函数如何被调用,对于箭头函数,this的值基于函数周围的上下文,换句话说,this的值和函数外面的this的值是一样的。
传递给 setTimeout() 的函数被调用时没用到 new、call() 或 apply(),也没用到上下文对象。意味着函数内的 this 的值是全局对象,不是 dessert 对象。实际上发生的情况是,创建了新的 scoops 变量(默认值为 undefined),然后递增(undefined + 1 结果为 NaN);
这个例子不知道写过多少回了,每当事件里想使用定时器啥的都要先将this转为that,在去用that。像下面这样:
ES6中的箭头就是用在此处!将setTimeout改为箭头函数:
这种表达式我见到过,但是只是不知道它代表默认参数函数的意思。
createGrid() 函数预期传入的是数组。它通过解构将数组中的第一项设为 width,第二项设为 height。如果数组为空,或者只有一项,那么就会使用默认参数,并将缺失的参数设为默认值 5。
出现错误,是因为 createGrid() 预期传入的是数组,然后对其进行解构。因为函数被调用时没有传入数组,所以出现问题。但是,我们可以使用默认的函数参数!
像上面这样倒着写吗?但是我却收到了一个错误,说width is undefined!后来想想语法规范,也就是说我那样写的话是给一个空的参数名字设置了一个默认值,也就是说参数名都为空了,在设置默认值又有什么意义呢?,所以:
就像使用数组默认值解构数组一样,函数可以让对象成为一个默认参数,并使用对象解构:
默认函数参数只是个简单的添加内容,但是却带来很多便利!与数组默认值相比,对象默认值具备的一个优势是能够处理跳过的选项。看看下面的代码:
在 createSundae() 函数使用对象默认值进行解构时,如果你想使用 scoops 的默认值,但是更改 toppings,那么只需使用 toppings 传入一个对象:
对于这个函数,如果想使用 scoops 的默认数量,但是更改 toppings,则必须以这种奇怪的方式调用你的函数:
因为数组是基于位置的,我们需要传入 undefined 以跳过第一个参数(并使用默认值)来到达第二个参数。
在ES5,甚至现在为止,我学到的都是老旧的创建对象的方式!!!今天学习到了!
这是目前我掌握的方法。但是ES 6是2016年正式发布的!!!也就是说我已经落后两年了!
ES6类只是一个语法糖,原型继续实际上在底层隐藏起来, 与传统类机制语言有些区别.
javascript中类其实只是function, 方法之间不能使用,也不用逗号区分属性和方法.
要添加静态方法,请在方法名称前面加上关键字 static,类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
关键字class带来其他基于类的语言的很多思想,但是没有向javascript中添加此功能
在子类构造函数中,在使用 this 之前,必须先调用超级类。
ES6还有很多新的特性!这里写的只是参见了https://www.jianshu.com/p/87008f4f8513上的一篇简书,真正要看的还是阮一峰的ES6教材!