《ECMAScript 6 入门》笔记
1、babel-polyfill
Bable默认只转换新的javascript语法,而不转换新的API,比如iterator、gennerator、set、map、proxy、reflect、symbol、promise等全局对象。
举例来说,ES6在Array对象上新增了Array.from方法,babel就不会转换这个方法,需要通过bable-polyfill来进行转换
2、ESLint
用于静态检查代码的语法和风格
3、let
- 用来声明变量,用法类似于var, 但是声明的变量,旨在let命令的代码块内有效。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
- 不存在变量提升
在var情况下,变量在声明之前使用,虽然值为undefined,但是不会报错,但是由于let不存在变量提升,因此会报错
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
- 暂时性死区
只要块级作用域内存在let命令,他所声明的变量就绑定在这个区域,不受外部影响
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
- 不允许重复声明
- 块级作用域
{{{{
{let insane = 'Hello World'}
console.log(insane); // 报错
}}}};
- 块级作用域与函数声明
在ES5中,函数只能在顶层作用域中声明,不能再块级作用域中声明,
const
- const声明一个只读的常量,一旦声明,常量的值就不能改变。
- const一旦声明,就必须立即初始化,不能六道以后复制,否则会报错。
- 本质
const实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
对于简单类型的数据(数值、字符串、布尔值),值就保存在指向的内存地址,因此等同于常量。
但对于复合类型的数据(主要是对象和数组),指向的只是一个指向实际数据的指针,const只能保证这个指针固定不懂,至于指向的数据结构是不是可变,就不能控制了
const foo = {};
// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only
若真的想将对象冻结,应该使用Object.freeze()
声明变量的六种方法
var function let const import class
顶层对象的属性
顶层对象,在浏览器环境指的是window对象,在node指的是global对象
ES5中,顶层对象和全局变量是等价的,而在ES6中,let、const、class声明的全局变量,不属于顶层对象的属性。
变量的结构赋值
从数组和对象中提取值,对变量进行赋值,被称之为解构。只要等号两边的模式相同,左边的变量就会被赋予对应的值。
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
只要某种数据结构具有Iterator接口,都可以采用数组形式的解构赋值。
字符串的扩展
ES6为字符串添加了遍历器接口,是的字符可以被for …of 循环遍历
for(let codePoint of 'foo'){
console.log(condePoint)
}
// f
// o
// o
includes(), startsWith(), endsWith()
传统上,只有indexOf方法可以用来判断一个字符串是否包含另一个字符串。es6提供了以下三种新方法
- includes() :返回布尔值,表示是否找到了参数字符串
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部
这三种方法都支持第二个参数,表示开始搜索的位置
repeat()
repeat()返回一个新字符串,表示将源字符串重复n次,只针对字符串做操作!
'x'.repeat(3) //xxx
模板字符串
let name ='cindy'
let a = `my name is ${name}`
console.log(a) //my name is cindy
若使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中
字符串模板中还能调用函数
function fn(){
return "Hello world"
}
`foo ${fn()} bar` //"foo Hello world bar"
大括号内可以放任意表达式、函数、变量
正则的扩展
数值的扩展
函数的扩展
函数参数允许指定默认值
function log(x,y = 'world'){
console.log(x,y);
}
log('Hello') // "Hello world"
log('Hello','cindy') // "Hello cindy"
log('Hello','') // "Hello"
函数的length属性
返回没有置顶默认值的参数个数
(function (a){}).length //1
(function (a=1){}),length //0
箭头函数
可以使用一个圆括号代表参数部分
var f = () =>5
//相当于
var f = function (){
return 5
}
var sum = (num1,num2)=>num1+num2;
//等同于
var sum = function (num1,num2){
return num1+num2;
}
箭头函数的使用注意点
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象!
- 不可以当作构造函数,也就是说,不能使用new,否则会抛出一个错误。
- 使用rest代替arguments对象
- 箭头函数不可以作为generator函数
this对象的指向是可变的,但是在箭头函数中,他是固定的
箭头函数根本没有自己的this,导致内部this就是外层代码块的this,正是因为没有this, 所以不能用作构造函数。
// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
// 等同于 ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}
//转换后的 ES5 版本清楚地说明了,箭头函数里面根本没有自己的this,而是引用外层的this。
请问下面的代码之中有几个this?
function foo() {
return () => {
return () => {
return () => {
console.log('id:', this.id);
};
};
};
}
var f = foo.call({id: 1});
var t1 = f.call({id: 2})()(); // id: 1
var t2 = f().call({id: 3})(); // id: 1
var t3 = f()().call({id: 4}); // id: 1
双冒号运算符
由于箭头函数并不适用于所有场合,因此“函数绑定”运算符,用来取代call、bind、apply调用
函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。
foo::bar;
// 等同于
bar.bind(foo);
foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);
const hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn(obj, key) {
return obj::hasOwnProperty(key);
}
代替函数的apply方法
由于扩展运算符可以展开数组,因此不再需要apply方法,下面是利用扩展运算符求一个数组最大元素的例子
//es5
Math.max.apply(null,[1,23,4,5,3])
//es6
Math.max(...[1,23,4,5,3])
//等同于
Math.max(1,23,4,5,3)
扩展运算符的应用
- 复制数组
es5中复制数组的时候只是复制了底层数据结构的指针,更改a2会影响a1,但使用了扩展运算符会避免这个问题
const a1=[1,2]
const a2=[...a1]
a2[0]=0
a2 //[0,2]
a1 //[1,2]
- 合并数组
[...arr1,...arr2,...arr3]
Array.from()
Array.from 方法用于将两类对象转为真正的数组。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.of()
Array.of()用于将一组数值,转换为数组
对象的扩展
属性的便利
- for…in 循环遍历对象自身的和继承的可枚举属性
- Object.keys(obj) 返回一个数组,包括对象自身(不含继承)所有枚举属性的键名
- Object.getOwnPropertyNames(obj) 返回一个数组,包含对象自身的所有属性的键名
- Object.getOwnPropertySymbols(obj)返回一个数组,包含对象自身的所有 Symbol 属性的键名。
- Reflect.ownKeys(obj) 返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
super 关键字
指向当前对象的原型对象
对象新增的方法
Object.is()
用来比较两个值是否严格相等。
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
Object.assign()
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。
const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
- Object.assign 实行的是浅拷贝
Set
类似于数组,但是成员的值都是唯一的,因此可以用来去重
[...new Set(array)]
上一篇: Apache Avro RPC简单示例