ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。也就是说,ES6就是ES2015。虽然目前并不是所有浏览器都能兼容ES6全部特性,但越来越多的程序员在实际项目当中已经开始使用ES6了。今天就来总结一下在工作中es6常用的属性方法。
一、let、const与 block 作用域
block块级作用域
ES6引入了块级作用域,块内部定义的变量,在外部是不可以访问的.
例子1
if(true){
// var flag = 123;
let flag = 123;
}
// console.log(flag);
//当使用var声明时可以打印,
// 但使用let声明就不能打印了,{}相当于一个块级作用域
直接使用{}也可以形成一个块级作用域
{
// 这里是块级作用域
let flag = 111;
console.log(flag);
}
console.log(flag);//这里会报错,不能获取到块级作用域里声明的变量
在块级作用域内部,变量也是只能先声明再使用
if(true){
console.log(flag);
let flag = 123;
}
let
ES6新增了let命令,用来生命变量。它的用法类似于var,但是所声明的变量,只在let
命令所在的代码块内有效。
for (let i = 0; i < 10; i++) {
}
console.log(i) //ReferenceError: i is not defined<br>
for(var i=0;i<10;i++){
}
console.log(i) //10
上面代码中,计数器i
只在for
循环体内有效,在循环体外引用就会报错。let具有块级作用域的。var不存在块级作用域问题,具有全局变量提示的问题存在.
let声明的变量不允许重复(在同一个作用域内)
let flag = 123;
let flag = 456;
console.log(flag);//会报错
let声明的变量不存在预解析
console.log(flag);
var flag = 123;
let flag = 123; //不再预解析,直接报错
for循环中的块级作用域使用
for (var i = 0; i < 3; i++) {
console.log(i);
}
console.log(i); //这里不会有问题,i变成了3,可以打印,var的作用域是全局的,所以不会报错
而使用let
for (let i = 0; i < 3; i++) {
// for循环括号中声明的变量只能在循环体中使用
console.log(i);
}
console.log(i);//会报错,无法获取i
const
const声明一个只读的常量,一旦声明,常量的值就不能改变。
const a = 2;
a = 20;
console.log(a) //TypeError: Assignment to constant variable.
上面代码表明改变常量的值会报错。
const
声明的变量不得改变值,这意味着,const
一旦声明变量,就必须立即初始化,不能留到以后赋值。
const a;
console.log(a)
上面代码表示,对于const
来说,只声明不赋值,就会报错。
let与const
1.都不能重复声明
2.都存在块级作用域问题
3.只在声明所在的块级作用域内有效。
二、模板字符串
模板字符串就是一种字符串的新的表现形式
(1)基本用法
let s1 = ` hello `
let s2 = ' hello '
(2)字符串和变量拼接
let s3 =" a " + s1 + " b " + s2;
let s4 = ` a ${s1} b ${s2}`;
(3)字符串换行
var box =`<div>
<p>
<span>123</span>
</p>
<p>${a1}</p>
</div>`;
模板字符串的出现,极大的改变传统字符串的拼接方法,减少代码出现错误的几率。提高开发效率
三、箭头函数(Arrow Functions)
ES6 中,箭头函数就是函数的一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体:
基本用法
//匿名函数
div.onclick=function(){
console.log("你好")
}
//箭头函数
div.onclick=()=>{
console.log("你好")
}
有一个参数的箭头函数
var fn=(a)=>{
console.log("abc");
}
//等价于:
var fn=a=>{
console.log("abc");
}
有2个及更多参数的箭头函数
var f=(a,b,c)=>{
console.log("abc")
}
即
//无形参
var f = () => 5;
// 等同于
var f = function () { return 5 };
//多个形参
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
箭头函数有几个使用注意点。
1、函数体内的this
对象,就是使用时所在的对象。
// ES3、ES5中普通函数
var name = '张三';
var person = {
name:'nicholas',
age:18,
fav:function(){
console.log(this);
console.log()
}
};
person.fav();
打印结果为
此时this指向的是使用它的对象,也就是person对象,即调用它的对象。
而使用箭头函数
//使用箭头函数
var person = {
name: 'nicholas',
age: 18,
fav: () => {
// 当前this对象(window)
console.log(this);
console.log('this');
}
};
person.fav();
打印结果
此时因为箭头函数是指向全局的,即window对象
箭头函数的this永远指向其父作用域,任何方法都改变不了,包括call,apply,bind。普通函数的this指向调用它的那个对象。
Javascript定时器中的this指向
var name = 'my name is window';
var obj = {
name: 'my name is obj',
fn: function () {
var timer = null;
clearInterval(timer);
timer = setInterval(function () {
console.log(); //my name is window
}, 1000)
}
}
在这里,从可以看出this的指向是window。
如果没有特殊指向,setInterval和setTimeout的回调函数中this的指向都是window。这是因为JS的定时器方法是定义在window下的。但是平时很多场景下,都需要修改this的指向。这里总结了几种:
(1)最常用的方法:在外部函数中将this存为一个变量,回调函数中使用该变量,而不是直接使用this。
var name = 'my name is window';
var obj = {
name: 'my name is obj',
fn: function () {
var that = this;
var timer = null;
clearInterval(timer);
timer = setInterval(function () {
console.log(); //my name is obj
}, 1000)
}
}
在fn中加了var that = this; 回调函数中使用that代替this即可。这种方法最常见,使用也最广泛。
(2)使用es6的箭头函数:箭头函数的最大作用就是this指向。
var name = 'my name is window';
var obj = {
name: 'my name is obj',
fn: function () {
var timer = null;
clearInterval(timer);
timer = setInterval(() => {
console.log(); //my name is obj
}, 1000)
}
}
箭头函数没有自己的this,它的this继承自外部函数的作用域。所以,在该例中,定时器回调函数中的this,是继承了fn的this。当然箭头函数也有兼容问题,要是兼容低版本ie,需要使用babel编译,并且引入es5-shim.js才可以。
2、不可以使用arguments
对象,该对象在函数体内不存在。
let foo = (a,b) => {
console.log(a,b);
// console.log(arguments);//这种方式获取不到实参列表
};
foo(123,456);
四、对象的简洁表示法
属性简写
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};
上面代码中,变量foo
直接写在大括号里面。这时,属性名就是变量名, 属性值就是变量值。下面是另一个例子。
function f(x, y) {
return {x, y};
}
// 等同于
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}
方法简写
const o = {
method() {
return "Hello!";
}
};
// 等同于
const o = {
method: function() {
return "Hello!";
}
};
例子2
let birth = '2000/01/01';
const Person = {
name: '张三',
//等同于birth: birth
birth,
// 等同于hello: function ()...
hello() { console.log('我的名字是', ); }
};
例子3
function getPoint() {
const x = 1;
const y = 10;
return {x, y};
}
getPoint()
// {x:1, y:10}
五、es6中的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
变量的解构赋值
以前,为变量赋值,只能直接指定值。
let a = 1;
let b = 2;
let c = 3;
ES6 允许写成下面这样。
let [a, b, c] = [1, 2, 3];
上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。
例子
let [a,b,c] = [,123,]; //与前面的数组是一一对应的关系,没有值就是undefined
console.log(a,b,c) //输出:undefined 123 undefined
let [a=111,b,c] = [,123,];//可以在前面设置默认值
console.log(a,b,c); //输出:111 123 undefined
对象的解构赋值
解构不仅可以用于数组,还可以用于对象。
let {foo,bar} = {foo : 'hello',bar : 'hi'};
let {foo1,bar1} = {bar1 : 'hi',foo1 : 'hello'};//改变key的顺序无影响
console.log(foo,bar);//打印的value
console.log(foo1,bar1);//打印的value
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
变量没有对应的同名属性,导致取不到值,最后等于undefined
。
let {foo} = {bar: 'baz'};
foo // undefined
变量没有对应的同名属性,导致取不到值,最后等于undefined
。
对象的解构赋值是下面形式的简写
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };
也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
对象属性别名(如果有了别名,那么原来的名字就无效了)
let {foo:abc,bar} = {bar : 'hi',foo : 'nihao'};
//给foo这个key设置别名,可以用别名,但原来的key就不能用了
console.log(abc,bar);
console.log(foo,bar);//会报错
如果解构失败,变量的值等于undefined。
对象的解构赋值指定默认值
let {foo:abc='hello',bar} = {bar : 'hi'};
console.log(abc,bar);
六、Class 的基本语法
JavaScript 语言中,生成实例对象的传统方法是通过构造函数。下面是一个例子。
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
上面这种写法跟传统的面向对象语言(比如 C++ 和 Java)差异很大,很容易让新学习这门语言的程序员感到困惑。
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class
关键字,可以定义类。
基本上,ES6 的class
可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用 ES6 的class
改写,就是下面这样
class Animal{
// 构造器 当你创建实例之后 constructor()方法会立刻调用 通常这个方法初始化对象的属性
constructor(name,age){
= name;
this.age = age;
}
showName(){
console.log();
}
}
var a2 = new Animal('点点',3);
上面代码定义了一个“类”,可以看到里面有一个constructor
方法,这就是构造方法,而this
关键字则代表实例对象。也就是说,ES5 的构造函数Animal,对应 ES6 的Animal类的构造方法。
Animal类除了构造方法,还定义了一个showName方法。注意,定义“类”的方法的时候,前面不需要加上function
这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。