ES6学习笔记
let命令
基本用法
ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量只能在let代码块中有效。
例如:
{ var a = 1; let b = 2; } console.log(a); //1 console.log(b); //Error: a is not defined
不存在变量的提升
let不会像var那样存在变量的提升
var a = []; for(var i = 0;i<10;i++){ var b = i; //ES5的写法 a[i] = function() { console.log(b); } } a[3](); //9 (这里因为使用了var使得变量提升,循环体满足条件才会跳出循环,所以最后输出结果也是9)
var a = []; for(var i = 0;i<10;i++){ let b = i; //ES6的写法 a[i] = function() { console.log(b); } } a[3](); //3 (这里为什么会是3呢,因为let只对循环体的内部起作用,它内部的b是影响不到外部的,所以最后输出的是3)
暂时性死区
只要块级作用域中存在let命令,它所声明的变量就绑定(binding)在这个区域中,不在受外部的影响。
var a = 10; { console.log(a); //undefined (作用域内部变量不受外部影响,还有就是let不存在变量提升,所以才会报未定义) let a = 3; console.log(a); //3 }
不允许有重复声明
let不允许在同一个作用域内,重复声明同一个变量
{ var a = 2; let a = 2; console.log(a) // Error: Identifier 'a' has already been declared }
块级作用域
为什么需要块级作用域?
ES5只用全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景
第一种场景,内层变量可能会覆盖外层变量
var time = new Date(); function fun() { console.log(time); if(false) { var time = 'hello world!'; //这里的time会优先提前,就会覆盖前面的全局变量 } } fun(); //undefined
第二种场景,用来计数的循环变量泄漏为全局变量
var t= "Hello world!"; for(var i=0; i < string.length;i++){ console.log(t[i]); } console.log('循环结束'); //循环结束 console.log(i); //12 (按理说这里循环体已经结束应该释放i中的内存占用,但是变量i中的内存没有释放,如果后面我们还要用到变量i的话就会影响i的值,所以这是很不合理的)
const 命令
const
声明一个只读的常量。一旦声明,常量的值就不能改变。
const a = 1; console.log(a); //1 a = 2; console.log(a); // TypeError: Assignment to constant variable
const
声明的变量不得改变值,这意味着,const
一旦声明变量,就必须立即初始化,不能留到以后赋值,不然就会报错。
const n; console.log(n); //SyntaxError: Missing initializer in const declaration
const
的作用域与let
命令相同:只在声明所在的块级作用域内有效;声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用;不允许重复声明。
箭头函数
我们经常需要给回调函数维护一个词法作用域的上下文 `this`。
一个常用的解决办法是把 `this` 存在一个变量中:
function Person(name) { this.name = name; } Person.prototype.prefixName = function (arr) { var that = this; // Store the context of this return arr.map(function (character) { return that.name + character; }); };
我们也可以传递一个合适的 `this` 上下文:
function Person(name) { this.name = name; } Person.prototype.prefixName = function (arr) { return arr.map(function (character) { return this.name + character; }, this); }
我们还可以绑定上下文:
function Person(name) { this.name = name; } Person.prototype.prefixName = function (arr) { return arr.map(function (character) { return this.name + character; }.bind(this)); };
使用 箭头函数,`this` 将不会受到影响,并且我们可以重写上面的函数:
function Person(name) { this.name = name; } Person.prototype.prefixName = function (arr) { return arr.map(character => this.name + character); };
箭头函数的常用写法是:
// 正常函数写法 function(){ console.log('hello') } //使用箭头函数 ()=>{console.log('hello')}
箭头函数还有一个好处就是简化回调函数。
// 正常函数写法 [1,2,3].map(function (x) { return x * x; }); // 箭头函数写法 [1,2,3].map(x => x * x);
拓展的对象功能
对象初始化简写
ES5我们对于对象都是以键值对的形式书写,是有可能出现键值对重名的。例如:
function people(name, age) { return { name: name, age: age }; }
键值对重名,ES6可以简写如下:
function people(name, age) { return { name, age }; }
ES6 同样改进了为对象字面量方法赋值的语法。ES5为对象添加方法:
const people = { name: 'sa', getName: function() { console.log(this.name) } }
ES6通过省略冒号与 function 关键字,将这个语法变得更简洁
const people = { name: 'sa', getName () { console.log(this.name) } }
ES6 对象提供了 Object.assign() 这个方法来实现浅复制。
Object.assign() 可以把任意多个源对象自身可枚举的属性拷贝给目标对象,然后返回目标对象。第一参数即为目标对象。在实际项目中,我们为了不改变源对象。一般会把目标对象传为{}
const objA = { name: 'cc', age: 18 } const objB = { address: 'shenzhen' } const objC = {} // 这个为目标对象 const obj = Object.assign(objC, objA, objB) // 我们将 objA objB objC obj 分别输出看看 console.log(objA) // { name: 'cc', age: 18 } console.log(objB) // { address: 'beijing' } console.log(objC) // { name: 'cc', age: 18, address: 'beijing' } console.log(obj) // { name: 'cc', age: 18, address: 'beijing' } // 是的,目标对象ObjC的值被改变了。 // 所以,如果objC也是你的一个源对象的话。请在objC前面填在一个目标对象{} Object.assign({}, objC, objA, objB)
更方便的数据访问--解构
数组和对象是JS中最常用也是最重要表示形式。为了简化提取信息,ES6新增了解构,这是将一个数据结构分解为更小的部分的过程
ES5我们提取对象中的信息形式如下:
const people = { name: 'lux', age: 20 } const name = people.name const age = people.age console.log(name + ' --- ' + age)
是不是觉得很熟悉,没错,在ES6之前我们就是这样获取对象信息的,一个一个获取。现在,解构能让我们从对象或者数组里取出数据存为变量,例如
//对象 const people = { name: 'sa', age: 20 } const { name, age } = people console.log(`${name} --- ${age}`) //数组 const color = ['red', 'blue'] const [first, second] = color console.log(first) //'red' console.log(second) //'blue'
面试题:
// 请使用 ES6 重构一下代码 // 第一题 var jsonParse = require('body-parser').jsonParse // 第二题 var body = request.body var username = body.username var password = body.password
// 1. import { jsonParse } from 'body-parser' // 2. const { body, body: { username, password } } = request
Spread Operator 展开运算符
ES6中另外一个好玩的特性就是Spread Operator 也是三个点儿...接下来就展示一下它的用途。
组装对象或者数组
//数组 const color = ['red', 'yellow'] const colorful = [...color, 'green', 'pink'] console.log(colorful) //[red, yellow, green, pink] //对象 const alp = { fist: 'a', second: 'b'} const alphabets = { ...alp, third: 'c' } console.log(alphabets) //{ "fist": "a", "second": "b", "third": "c" }
有时候我们想获取数组或者对象除了前几项或者除了某几项的其他项
//数组 const number = [1,2,3,4,5] const [first, ...rest] = number console.log(rest) //2,3,4,5 //对象 const user = { username: 'lux', gender: 'female', age: 19, address: 'peking' } const { username, ...rest } = user console.log(rest) //{"address": "peking", "age": 19, "gender": "female" }
对于 Object 而言,还可以用于组合成新的 Object 。(ES2017 stage-2 proposal) 当然如果有重复的属性名,右边覆盖左边
const first = { a: 1, b: 2, c: 6, } const second = { c: 3, d: 4 } const total = { ...first, ...second } console.log(total) // { a: 1, b: 2, c: 3, d: 4 }
未完,持续更新中……