ES6使用相关
当需要一个只有一个参数的简单函数时,可以使用新标准中的箭头函数,它的语法非常简单:标识符=>表达式。你无需输入function和return,一些小括号、大括号以及分号也可以省略。
简化了函数的书写,Input=>outputs
var array = [1,2,3];
array.forEach(function(v,i,a){
console.log(v);
});
//ES6
array.forEach(v=>console.log(v));
如果要写一个接受多重参数(也可能没有参数,或者是不定参数、默认参数、参数解构)的函数,你需要用小括号包裹参数list。
// ES6
var total = values.reduce((a, b) => a + b, 0);
var num=Math.random();
console.log(`your num is ${num}`);
##4. let命令 let命令:用于声明变量。用法类似于var,区别在于let所声明的变量,只在let命令所在的代码块内部有效。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
这段代码中for循环内部用let命令声明变量i,只在本轮循环内有效,所以每一次循环时i都是一个新值,所以最后输出6。
如果for循环内用var声明变量i,在全局范围内都有效,所以每一次循环i的新值都会覆盖旧值,所以最后输出10。
console.log(a); let a = 2;
let命令不存在“变量提升”现象,变量一定要在声明之后使用,否则会报错。 暂时性死区:只要块级作用域中存在let命令,所声明的变量就绑定在这个区域,不再受外部影响
例如:
var t = 1;
if(true) {
t = 'a';
let t;
}
因为在块级作用域中用let又声明了一个局部变量t,导致变量t绑定在这个块级作用域,所以在let声明变量t之前,对t赋值会报错。
不允许重复声明:let不允许在相同作用于内重复声明同一变量。
function func(arg) {
let arg; // 报错
}
function func(arg) {
{
let arg; // 不报错
}
}
不能在函数内部重新声明参数
const命令也用来声明变量,但是只可声明常量,一旦声明,常量的值不能再被改变。 一旦声明,必须初始化,其他用法大致与let相同。
跨模块常量:
直接调用父类方法
//通过对象字面量创建对象
var human = {
breathe() {
console.log('breathing...');
}
};
var worker = {
__proto__: human, //设置此对象的原型为human,相当于继承human
company: 'freelancer',
work() {
console.log('working...');
}
};
human.breathe();//输出 ‘breathing...’
//调用继承来的breathe方法
worker.breathe();//输出 ‘breathing...’
##7. ES6的块级作用域
以前为变量赋值时只可以:
var a = 1;
var b = 2;
var c = 3;
现在可以写成这样:
var [a, b, c] = [1, 2, 3];
从数组中提取值,按照对应位置,对变量赋值
属于“模式匹配”,等号两边模式相同就会相应赋值,结构不成功时变量的值就等于undefined 等号左边的模式匹配一部分右边的数组时,解构也是成功的,属于不完全解构。
如果右边不是可以遍历的结构就会报错 let和const命令也适用。 默认值:解构赋值允许指定默认值。 但如果数组成员不严格等于undefined,默认值就不会生效
惰性求值:如果默认值是一个表达式,只有在用到的时候才会求值。
function f(){
console.log("aaa");
}
let [x = f()] = [1];
上面代码因为x可以取到值所以f()不会执行。
对象的属性没有顺序,变量必须与属性同名,才能取到正确的值
var { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
若不同名,则必须写为:
var { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
被赋值的是变量 不是模式。 其余与数组解构类似。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
此时,字符串被转换成了一个类似数组的对象。 会有length属性,也可以解构赋值
let {length : len} = 'hello';
len // 5
函数的参数也可以使用解构赋值,并且也可以使用默认值。 不能使用圆括号的三种情况:
变量声明语句中,模式不能带有圆括号。
var [(a)] = [1];
var { x: (c) } = {};
var { o: ({ p: p }) } = { o: { p: 2 } };
以上三种写法全部会报错。
只有赋值语句的非模式部分才可以使用圆括号。
模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
将不同功能的代码写在不同的文件中
//user.js
module "user"{
export class User{
constructor (x,y) {
public x = x;
public y = y;
}
}
}
//app.js
//声明所要引用的模块
module user from "/user.js";
import User from "user";
var o = new User(1,3);
console.log(o);
ES6中像Java一样增加了对于类的支持,可以在JavaScript中用class定义类。使我们在JavaScript中对象的创建和继承更加清楚直观。
class Animal {
//ES6中新型构造器
constructor(name) {
this.name = name;
}
//实例方法
sayName() {
console.log('My name is '+this.name);
}
}
//类的继承
class Dog extends Animal {
constructor(name) {
//直接调用父类构造器进行初始化
super(name);
}
program() {
console.log("I'm coding...");
}
}
//测试
var animal=new Animal('dummy'),
wayou=new Dog('wayou');
animal.sayName();//输出 ‘My name is dummy’
wayou.sayName();//输出 ‘My name is wayou’
wayou.program();//输出 ‘I'm coding...’
ps:java中解释super()是当前对象的直接父类的无参的构造函数。
使用 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不会保存它的值,也就是说这次添加其实没有意思
可以监听对象身上发生什么变化
//定义被监听的目标对象
var e = { name: 'Joe', salary: 50 };
//定义处理程序
var i = {
set: function (receiver, property, value) {
console.log(property, 'is changed to', value);
receiver[property] = value;
}
};
//创建代理以进行侦听
e = Proxy(e, i);
//做一些改动来触发代理
e.salary = 60;//控制台输出:salary is changed to 60
如果监听的对象属性被更改,处理程序就会被调用
Proxy支持的拦截操作一览。
对于可以设置、但没有设置拦截的操作,则直接落在目标对象上,按照原先的方式产生结果。
(1)get(target, propKey, receiver)
拦截对象属性的读取,比如proxy.foo和proxy[‘foo’],返回类型不限。最后一个参数receiver可选,当target对象设置了propKey属性的get函数时,receiver对象会绑定get函数的this对象。
(2)set(target, propKey, value, receiver)
拦截对象属性的设置,比如proxy.foo = v或proxy[‘foo’] = v,返回一个布尔值。
(3)has(target, propKey)
拦截propKey in proxy的操作,返回一个布尔值。
(4)deleteProperty(target, propKey)
拦截delete proxy[propKey]的操作,返回一个布尔值。
(5)enumerate(target)
拦截for (var x in proxy),返回一个遍历器。
(6)hasOwn(target, propKey)
拦截proxy.hasOwnProperty(‘foo’),返回一个布尔值。
(7)ownKeys(target)
拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一个数组。该方法返回对象所有自身的属性,而Object.keys()仅返回对象可遍历的属性。
(8)getOwnPropertyDescriptor(target, propKey)
拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
(9)defineProperty(target, propKey, propDesc)
拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
(10)preventExtensions(target)
拦截Object.preventExtensions(proxy),返回一个布尔值。
(11)getPrototypeOf(target)
拦截Object.getPrototypeOf(proxy),返回一个对象。
(12)isExtensible(target)
拦截Object.isExtensible(proxy),返回一个布尔值。
(13)setPrototypeOf(target, proto)
拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。
如果目标对象是函数,那么还有两种额外操作可以拦截。
(14)apply(target, object, args)
拦截Proxy实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)。
(15)construct(target, args, proxy)
拦截Proxy实例作为构造函数调用的操作,比如new proxy(…args)。
##15. Symbols
symbol是一种基本类型
let s = Symbol();
typeof s
// "symbol"
可以用symbol这种值作为对象的键
Symbol通过调用symbol函数产生,有一个可选的名字的参数,凡是属性名属于Symbol类型,就都是独一无二的。
Symbol还可以用来创建私有属性,外部无法直接访问
Symbol函数的参数只是表示对当前Symbol值的描述,因此相同参数的Symbol函数的返回值是不相等的。
// 没有参数的情况
var s1 = Symbol();
var s2 = Symbol();
s1 === s2 // false
// 有参数的情况
var s1 = Symbol("foo");
var s2 = Symbol("foo");
s1 === s2 // false
异步操作的一种模式,比如jQuery中的deferred对象 Promise对象是一个构造函数,用来生成Promise实例。
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在成功时调用,并将结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected),在失败时调用,并将报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。
promise.then(function(value) {
// success
}, function(value) {
// failure
});
Generator函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield语句就是暂停标志。
遍历器对象的next方法的运行逻辑如下。
(1)遇到yield语句,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield语句。
(3)如果没有再遇到新的yield语句,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
需要注意的是,yield语句后面的表达式,只有当调用next方法、内部指针指向该语句时才会执行,因此等于为JavaScript提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。
Generator函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在Generator函数体内捕获。
Generator函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历Generator函数。
用来在一个Generator函数里面执行另一个Generator函数。
JavaScript中允许采用\uxxxx形式表示一个字符,其中“xxxx”表示字符的码点,只限于\u0000——\uFFFF之间的字符,但在ES6中将码点放入大括号就可以正确解读超出范围的字符。 JavaScript有六种方法可以表示一个字符:
'\z' === 'z' // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true
codePointAt方法会正确返回32位的UTF-16字符的码点。对于那些两个字节储存的常规字符,它的返回结果与charCodeAt方法相同。(返回的是十进制) codePointAt方法的参数是字符在字符串中的位置(从0开始),
ES5提供的String.fromCharCode方法,用于从码点返回对应字符。但是这个方法不能识别32位的UTF-16字符。 ES6提供了String.fromCodePoint方法,可以识别0xFFFF的字符,弥补了String.fromCharCode方法的不足。在作用上,正好与codePointAt方法相反,如果有多个参数,则会合并成一个字符串返回。
ES7提供了字符串实例的at方法,可以识别Unicode编号大于0xFFFF的字符,返回正确的字符。Chrome浏览器已经支持该方法。是对ES5中charAt方法的扩展。
ES6提供了三种新方法来确定一个字符串是否包含在另一个字符串中:
三种方法都支持第二个参数,代表开始搜索的位置。 其中endWith方法使用第二个参数n时针对qiann个字符,而其他两种方法针对从第n个位置到字符串结束。
repeat方法返回一个新的字符串,将原来的字符串重复n次,参数如果是小数会被取整,如果是负数或者是Infinity,会报错,如果是0到-1之间的小数等同于0,NaN等同于0,如果参数是字符串则会先转换成数字。
'hello'.repeat(3) // "hellohellohello"
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。 像这样:
$("#result").append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
String.raw方法,用来充当模板字符串的处理函数,返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,将所有变量替换,对应于替换变量后的模板字符串。 如果原字符串的斜杠已经被转义就不会做任何处理
ES6提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。 如果要将0b和0x前缀的字符串数值转为十进制,要使用Number方法。
ES6在Number对象上,新提供了Number.isFinite()和Number.isNaN()两个方法,用来检查Infinite和NaN这两个特殊值。 这两个新方法只对数值有效,非数值一律返回false。
ES6将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。
// ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
Number.isInteger()用来判断一个值是否为整数。需要注意的是,在JavaScript内部,整数和浮点数是同样的储存方法,所以3和3.0被视为同一个值。
ES6在Number对象上面,新增一个极小的常量Number.EPSILON。
JavaScript能够准确表示的整数范围在-2^53到2^53之间(不含两个端点),超过这个范围,无法精确表示这个值。
ES6引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。
Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内。
ES6在Math对象上新增了17个与数学相关的方法。所有这些方法都是静态方法,只能在Math对象上调用。
ES7新增了一个指数运算符(**),目前Babel转码器已经支持。
二进制数组(ArrayBuffer对象,TypedArray视图和DataView视图),是JavaScript操作二进制数据的一个接口。
二进制数组由三类对象组成:
代表储存二进制数据的一段内存,不能直接读写,只能通过视图读写。 也是一个构造函数,可以分配一段可以存放数据的连续内存区域。
视图的作用:以指定的格式解读二进制数据。
var buf = new ArrayBuffer(32);
var dataView = new DataView(buf);
dataView.getUint8(0) // 0
上面代码中ArrayBuffer对象生成了一段32字节的内存区域,每个字节的默认值都是0,然后对这段字节指定视图。 TypedArray视图与DataView视图的一个区别是,它不是一个构造函数而是一组构造函数,代表不同的数据格式
var buffer = new ArrayBuffer(12);
var x1 = new Int32Array(buffer);
x1[0] = 1;
var x2 = new Uint8Array(buffer);
x2[0] = 2;
x1[0] // 2
TypedArray视图的构造函数还可以接受普通数组作为参数,直接分配内存生成底层的ArrayBuffer实例,并且同时完成赋值。
TypedArray视图一共包括9种类型,每一种视图都是一种构造函数。
Int8Array:8位有符号整数,长度1个字节。 Uint8Array:8位无符号整数,长度1个字节。 Uint8ClampedArray:8位无符号整数,长度1个字节,溢出处理不同。 Int16Array:16位有符号整数,长度2个字节。 Uint16Array:16位无符号整数,长度2个字节。 Int32Array:32位有符号整数,长度4个字节。 Uint32Array:32位无符号整数,长度4个字节。 Float32Array:32位浮点数,长度4个字节。 Float64Array:64位浮点数,长度8个字节。
由这9个构造函数生成的数组,统称为TypedArray视图。
每一种视图的构造函数都有一个BYTES_PER_ELEMENT属性,表示这种数据类型占据的字节数
相互之间转换时,需要字符串的编码方法是确定的
如果一段数据包括多种类型(比如服务器传来的HTTP数据),这时除了建立ArrayBuffer对象的复合视图以外,还可以通过DataView视图进行操作。
Set是一种新的数据结构,类似数组,但是成员的值都是唯一的并且没有重复值,本身是一个构造函数,用来生成Set数据结构 Set函数可以接受一个数组(或者一个类似数组的对象)作为参数,用来初始化。
Set实例的四个操作方法。
遍历操作:可以用于遍历成员。
Set结构没有键名,只有键值(或者说键名和键值是同一个值)
ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。
var m = new Map();
var o = {p: "Hello World"};
m.set(o, "content")
m.get(o) // "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false
作为构造函数,Map也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。
如果对同一个键多次赋值,后面的值将覆盖前面的值。
在每次循环中循环的是值而不是序号 可以正确响应break、continue和return语句 for-of循环不支持普通对象
for…of循环可以使用的范围包括数组、Set和Map结构、某些类似数组的对象(比如arguments对象、DOM NodeList对象)、后文的Generator对象,以及字符串。
Iterator的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费。
Iterator的遍历过程:
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。