ECMAScript发生了哪些变化
JavaScript是ECMAScript的实现和扩展,由ECMA(一个类似W3C的标准组织)参与进行标准化。ECMAScript定义了:
ECMAScript标准不定义HTML或CSS的相关功能,也不定义类似DOM(文档对象模型)的Web API,这些都在独立的标准中进行定义。ECMAScript涵盖了各种环境中JS的使用场景,无论是浏览器环境还是类似node.js的非浏览器环境。
ECMAScript6的到来
ES6是一次重大的版本升级,与此同时,由于ES6秉承着最大化兼容已有代码的设计理念,你过去编写的JS代码将继续正常运行。事实上,许多浏览器已经支持部分ES6特性,并将继续努力实现其余特性。这意味着,在一些已经实现部分特性的浏览器中,你的JS代码已经可以正常运行。如果到目前为止你尚未遇到任何兼容性问题,那么你很有可能将不会遇到这些问题,浏览器正飞速实现各种新特性。
既然es6的时代已经来临了,那么我们就不能停止不前固守成规了,下面我们就来看一下这些新特性
具体特性
1. 箭头操作符
你肯定知道一些高级语言中(例如java),有lambda表达式,es6新增的=>箭头操作符和他相似。他简化了我们在js中一些回调函数的简写。操作符左边是输入的参数,操作符右边是进行的操作以及返回的值,arugs=>output。
var arr=[1,2,3,4,5];
//传统写法
arr.forEach(function(v,i,a){console.log(v)})//2,3,4,5,6
//箭头操作符写法
arr.forEach(x=>console.log(x+1))//2,3,4,5,6
2. class
ES6中添加了对类的支持,引入了class关键字(其实class在JavaScript中一直是保留字,目的就是考虑到可能在以后的新版本中会用到,现在终于派上用场了)。JS本身就是面向对象的,ES6中提供的类实际上只是JS原型模式的包装。现在提供原生的class支持后,对象的创建,继承更加直观了,并且父类方法的调用,实例化,静态方法和构造函数等概念都更加形象化。
class Car{
constructor(name,color){ //构造函数
this.color=color;
this.name=name;
};
showCar(){
alert(this.name);
}
}
var bmw=new Car("BMW");
bmw.showCar();//BMW
class Train extends Car{
constructor(name,color,price){
super(name,color); //继承父类
this.price=price;
}
showPrice(){
alert(alert(this.name+"的价格是:"+this.price))
}
}
var bmw2=new Train("BMW","red","70w");
bmw2.showPrice(); //BMW的价格是:70W
3. 对象字面量被增强了
对象字面量被增强了,写法更加简洁与灵活,同时在定义对象的时候能够做的事情更多了。具体表现在:
- 可以在对象字面量里面定义原型
- 定义方法可以不用function关键字
- 直接调用父类方法
var car={
sale(){console.log("im saleing...")} //可以省去function关键字
};
var BMW={
__proto__:car, //设置此对象的原型是car,相当于继承car
work(){console.log("im working...")}
};
car.sale(); //im saleing...
BMW.sale(); //im saleing...
BMW.work(); //im working...
4.字符串模板
ES6中允许使用反引号 ` 来创建字符串,此种方法创建的字符串里面可以包含由美元符号加花括号包裹的变量${vraible}。
var name="xwk";
alert(`My name is ${name}`)
//My name is xwk
5. 解构
自动解析数组或对象中的值。例如,一个函数要返回多个值, 以前的做法是返回一个对象,将每个值作为对象的属性返回。但是在es6中,可以使用解构的方法,可以直接返回一个数组,然后数组中的值会被自动解析到对象该数组的变量中。
var [a,b,c]=getVal(); //函数返回值的解构
var [x,,y]=["a","b","c"]; //数组的解构
function getVal() {
return [1,2,3];
}
console.log(a+","+b+","+c); //1,2,3
console.log(x+y); //ac
解构的好处与用途:(2017/3/7补)
//1.交换值
let a=1;
let b=2;
[a,b]=[b,a];
//2.从函数返回多个值
function getData(){
return [1,2,3]
}
let [a,b,c]=getData();
//3.提取json对象
let jsonData={
id:12,
name:"xwk",
data:["1234","acdf"]
}
let {id,name,data}=jsonData
//4.遍历map
let map=new Map();
map.set("first","hello");
map.set("second","world");
for(let [key,value] of map)
{
console.log(key+"is"+value);
}
6. let和const关键字(2017/3/7补)
1.你是否为js语言没有块级作用域而困惑烦恼过,强迫症们的福利来了,es6新增了let关键字,就类似于块级作用域的效果,let定义的变量只在当前特定环境中有效。
//使用var定义
if(1){
var i=2;
}
alert(i) //2,因为没有块级作用域
//使用let定义
if(1){
let i=2;
}
alert(i) //报错,原因是i只在条件语句中声明过,全局中没有该变量
2.let定义的变量,不存在变量提升
//使用var定义
console.log(i); //undefined 因为存在变量提升 相当于先声明后赋值
var i=111;
//使用let定义
console.log(i); //undefined 因为不存在变量提升 所以会报错
let i=111;
3.暂时性的死区(temporal dead zone,简称 TDZ)
在代码块内,只要在let声明变量之前使用变量,都是不合法的
var name="xwk";
if(1){
name="wkx"; //ReferenceError 暂时性的死区
let name;
} //因为在if块内部,使用let声明了一个局部变量name,在声明之前的都是属于TDZ,所以直接赋值会报错
4.使用let声明的变量不许重复声明(const一样)
let name = "xwk";
let name = "xwk2"; //Error
5.do
do表达式把块级的结果值返回
let x = do {
let t = f();
t * t + 1;
};
6.const用来定义常量,不可修改。
7.for of遍历
我们都知道for in 循环用于遍历数组,类数组或对象,ES6中新引入的for of循环功能相似,不同的是每次循环它提供的不是序号而是值。
var someArray = [ "a", "b", "c" ];
for (v of someArray) {
console.log(v); //输出 a,b,c
}
8. 模块化
在ES6标准中,JavaScript原生支持module了。这种将JS代码分割成不同功能的小块进行模块化的概念是在一些三方规范中流行起来的,比如CommonJS,requireJs和AMD模式。(require.js在后面的博客中会持续更新。。)
// point.js
module "point" {
export class Point {
constructor (x, y) {
public x = x;
public y = y;
}
}
}
// myapp.js
//声明引用的模块
module point from "/point.js";
//这里可以看出,尽管声明了引用的模块,还是可以通过指定需要的部分进行导入
import Point from "point";
var origin = new Point(0, 0);
console.log(origin);
9.Map,Set 和 WeakMap,WeakSet
这些是新加的集合类型,提供了更加方便的获取属性值的方法,不用像以前一样用hasOwnProperty来检查某个属性是属于原型链上的呢还是当前对象的。同时,在进行属性值添加与获取时有专门的get,set 方法
// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;
// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;
有时候我们会把对象作为一个对象的键用来存放属性值,普通集合类型比如简单对象会阻止垃圾回收器对这些作为属性键存在的对象的回收,有造成内存泄漏的危险。而WeakMap,WeakSet则更加安全些,这些作为属性键的对象如果没有别的变量在引用它们,则会被回收释放掉,具体还看下面的例子
// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined
// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });//因为添加到ws的这个临时对象没有其他变量引用它,所以ws不会保存它的值,也就是说这次添加其实没有意思
10.Symbols
我们知道对象其实是键值对的集合,而键通常来说是字符串。而现在除了字符串外,我们还可以用symbol这种值来做为对象的键。Symbol是一种基本类型,像数字,字符串还有布尔一样,它不是一个对象。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。之后就可以用这个返回值做为对象的键了。Symbol还可以用来创建私有属性,外部无法直接访问由symbol做为键的属性值。
(function() {
// 创建symbol
var key = Symbol("key");
function MyClass(privateData) {
this[key] = privateData;
}
MyClass.prototype = {
doStuff: function() {
... this[key] ...
}
};
})();
var c = new MyClass("hello")
c["key"] === undefined//无法访问该属性,因为是私有的