ES6新特性

1.箭头函数(=>)

ES6中引入了箭头函数符来代替function,也就是说在定义方法的时候可以不再写function,=>的左边即为函数名和参数,右边即为执行操作和返回值。

例如:

function(i){return i + 1; } //ES5
(i) => i + 1 //ES6


如果方法比较复杂,则执行的操作需要用{}包裹起来。例如:

function(x, y) { 	//ES5
    x++;
    y--;
    return x + y;
}	
(x, y) => {x++; y--; return x+y}	//ES6


 

引入箭头函数不仅使得写法更加简洁清晰,同时也解决了js中this作用域的问题。

在ES5中,函数当中的this仅指代当前函数,如果函数当中还包含函数,那么this的使用就需要相当小心。例如:

class Animal {
    constructor(){
        this.type = 'animal'	//这里的this指代Animal对象
    }
    says(say){
        setTimeout(function(){
            console.log(this.type + ' says ' + say)//这里的this紧指代setTimeout的执行函数,而该函数中并没有type属性
        }, 1000)
    }
}

 var animal = new Animal()
 animal.says('hi')  //undefined says hi

传统的做法有以下2种:
第一种:声明一个变量指代最外层对象的this,然后在内层函数中使用该变量。例如:
says(say){
       var self = this;
       setTimeout(function(){
           console.log(self.type + ' says ' + say)
       }, 1000)
}

第二种:使用bind(this),bind方法会新创建一个绑定函数,当调用这个绑定函数的时候会以bind方法的第一个参数修改函数内部的this指向。例如:

says(say){
       setTimeout(function(){
           console.log(this.type + ' says ' + say)
       }.bind(this), 1000)//用says的this对象替代setTimeout执行方法的this对象
}


由于箭头函数内部并没有定义this对象,所以函数内部的this完全是继承的外部的,所以ES6中将不必担心上面的问题。例如:

lass Animal {
    constructor(){
        this.type = 'animal'
    }
    says(say){
        setTimeout( () => {
            console.log(this.type + ' says ' + say)
        }, 1000)
    }
}
 var animal = new Animal()
 animal.says('hi')  //animal says hi

2.变量声明(let、const)

ES6中新引入了2个变量的声明let和const,他们的作用基本跟var相同,具体区别如下:
var 声明的变量作用在全局或者方法体内。块级变量只能使用全局变量或方法体的变量。

let声明的变量只作用在代码块。可以完全使用let代替var。

const只是用来声明常量的,且一旦声明常量的值就不能改变了。能够更清晰的表明这是常量,不能修改。


先来看一个let和var使用区别的例子:

var name = 'zach'

while (true) {
    var name = 'obama'
    console.log(name)  //obama
    break
}

console.log(name)  //obama
//由于var作用域只有全局和函数内部,所以第二次声明的作用域跟第一次声明一致。


let name = 'zach'

while (true) {
    let name = 'obama'
    console.log(name)  //obama
    break
}

console.log(name)  //zach
//let的作用域只存在于块级内部。


var由于作用域的问题存在循环变量泄漏为全局变量的问题。如下:

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

上面代码就是因为i被泄漏为了全局变量,当循环完成后i已经为10了,所以无论数组下标是几的结果都是10。


传统的解决方案是采用闭包。例如:

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = getA(i);
}
function getA(i){
  var showA = function () {
    console.log(i);
  };

  return showA;
}

a[6](); // 6


ES6使用let的解决方法如下:

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6


const只是用来声明常量,当我们试图修改它声明的常量时,浏览器会报错。

其最好的应用场景是,当我们引入第三方插件库的时候可以保证插件声明不重复。

需注意:静态字符串声明统一使用单引号或反引号,不使用双引号,动态字符串使用反引号。例如:

const PI = Math.PI
const monent = require('moment')
const b = `foo${a}bar`;


3.类的支持(class,extends,super)

ES6引入了class关键字让对象的声明定义前后端更加一致。
ES5中,定义一个对象如下:
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);

在ES6中则可以使用如下形式:
//定义类
class Point {
  constructor(x, y) {//默认自带的构造函数,不显示声明则是个空的
    this.x = x;
    this.y = y;
  }

  toString() {
    return this.x + ', ' + this.y;
  }
}

class Line extends Point {
	constructor(m,n,l){
		super(m,n);//调用父类的构造函数
		this.l = l;
	}
	
	toLine(){
		return '('+this.l +','+ super.toString()+')';
	}
} 

var p = new Point(2,3);
var l = new Line(2,3,4);
p.toString();	//2,3
l.toString();	//2,3
l.getSum();	//(4,2,3)

需注意几点:
1.子类必须在constructor中调用super后才能使用this对象。
2.如果子类不显示定义一个constructor,那么会存在一个默认的constructor(...args){super(...args)}方法
3.对象.prototype.constructor = 对象本身
4.子类的__proto__属性,表示构造函数的继承,总是指向父类。(即:Line._proto_=Point)

5.子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的(即:Line.prototype._proto_=Point.prototype


4.字符串模版

ES6中允许使用反引号 ` 来创建字符串,此种方法创建的字符串里面可以包含${vraible}的变量。模版字符串会保留反引号包裹的所有空格和换行,如果其中含有反引号,需要\`进行转义。如需去掉换行,可以调用trim()。
ES5中定义一个模版示例如下:
$('#result').append(
  'There are <b>' + basket.count + '</b> ' +
  'items in your basket, ' +
  '<em>' + basket.onSale +
  '</em> are on sale!'
);

ES6则更将简洁方便。
$('#result').append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

5.参数

a.默认参数
ES6中允许在定义函数的时候指定参数默认值,例如name=“value”,但是这里并不是赋值操作,而是如果传了参数,那么使用参数值,如果没有传参数,那么使用默认值。示例如下:
function sayHello(name){
	//传统的指定默认参数的方式
	var name=name||'dude';
	console.log('Hello '+name);
}
//运用ES6的默认参数
function sayHello2(name='dude'){
	console.log(`Hello ${name}`);
}
sayHello();//输出:Hello dude
sayHello('Wayou');//输出:Hello Wayou
sayHello2();//输出:Hello dude
sayHello2('Wayou');//输出:Hello Wayou

b.不定参数
这是一个好用的语法糖,可以指定参数名称,以...args 的形式传入不定个数的参数。在ES5中我们可以使用 arguments变量来实现这一目的,arguments代表了一个Arguments对象。

ES5中传入多个参数的实现如下:
function add(){
         var n = arguments.length;
         var sum = 0;
         for (var i = 0; i < arguments.length; i++) {
                sum = sum + arguments[i];
         }
	return sum;
}
console.log(add(1,2,3));//6

ES6中传入多个参数的实现如下:
//将所有参数相加的函数
function add(...x){
	return x.reduce((m,n)=>m+n);
}

//传递任意个数的参数
console.log(add(1,2,3));//输出:6

c.拓展参数
这是另一种形式的语法糖,它允许传递数组或者类数组直接做为函数的参数而不用通过apply
var people=['Wayou','John','Sherlock'];

function sayHello(people1,people2,people3){
	console.log(`Hello ${people1},${people2},${people3}`);
}
//但是我们将一个数组以拓展参数的形式传递,它能很好地映射到每个单独的参数
sayHello(...people);//输出:Hello Wayou,John,Sherlock 

//而在以前,如果需要传递数组当参数,我们需要使用函数的apply方法
sayHello.apply(null,people);//输出:Hello Wayou,John,Sherlock

6.模块

ES6中让js支持了模块概念,我们不需要再去引用其他的js框架(如requireJS)来实现前端的模块化。但需遵循如下规则:

a.每一个模块只加载一次, 每一个JS只执行一次, 如果下次再去加载同目录下同文件,直接从内存中读取。 一个模块就是一个单例,或者说就是一个对象;

b.每一个模块内声明的变量都是局部变量, 不会污染全局作用域;

c.模块内部的变量或者函数可以通过export导出,且export导出的名称必须和定义的名称一一对应;

d.一个模块可以导入别的模块


//lib.js
//导出常量
export const sqrt = Math.sqrt;
//导出函数
export function square(x) {
    return x * x;
}
//导出函数
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}

//main.js
import { square, diag } from './lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

模块的导出有5种方式:
export{函数名或变量名};
export{函数名或变量名 as 别名};
export  函数或变量;
export defalut 函数或变量;
export * from js路径;

//lib.js文件
let fn0 = function() {
    console.log("fn0");
};
let obj0 = {}
export { fn0 as foo, obj0 as bar};

test.js
export let test = ()=> console.log("test"),a = "1";
export defalut b = "2";	//默认导出可以任意设置导入名称


//main.js文件
import {foo, bar} from "./lib";
import * form "./test.js";  //相当于继承了test.js中的所有方法属性,但是除开defalut定义的内容。
import c form ".test.js";  //导入defalut定义的b,因为是默认导入所以名字随便取

foo();
console.log(a);
console.log(c);


7.解构

ES6中可以自动解析数组会对象的值。
let [a,b,c] = ["1","2","3"];
let {name,age} = {name:"zhangsan",age:24} 
console.log(b);//2
console.log(`${name},${age}`);//zhangsan,24

需注意:等号2边最好一一对应,但是允许左边少右边多,这种情况将只匹配右边对应的一部分值。
解构实际上就是让等号2边一一对应,省去了赋值的操作。

8.循环遍历

ES6中引入了for...of...遍历方式,这种循环遍历方式和for...in...有些类似,但是for...in...中的变量是对象的属性名或者数组的下标值。而for...of...中的变量是直接的数组具体值。
let objArr = [{
		name:'zhangsan',
		gender:'男'
	},
	{
		name:'李四',
		gender:'女'
	}]
for(let obj of objArr){
	console.log(obj .name+','+obj.gender);
}
//zhangsan,男
//李四,女

for...of是基于Iterator接口实现的。ES6为字符串实现了该接口,所以字符串可以被遍历。

Iterator的遍历过程是这样的。

(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。

(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。

(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。

(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。

每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含valuedone两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。


模拟一个next()返回值的方法。
var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}


9.对象扩展

a.字符串对象新方法
//(1)at():相比于charAt(),可识别码值
'abc'.at(0) // "a"

//(2)repeat(n):将原字符串重复n次
'ab'.repeat(2);	//abab

//(3)padStart(str,n):以str字符串补全头部,字符串最小长度为n
//   padEnd(str,n):以str字符串补全尾部,字符串的最小长度为n
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'

'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'

//(4)includes(str,n):返回布尔值,从第n个位置开始查找是否包含str字符串,n可省略默认为0。
//      startsWith(str,n):返回布尔值,从第n个位置开始查找,str字符串是否在源字符串头部,n可省略默认为0。
//      endsWith(str,n):返回布尔值,从第你n个位置向前查找,str是否在源字符串末尾,n可省略,默认为源字符串长度。
var s = 'Hello world!';

s.startsWith('Hell') // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false

b.Map、Set、WeakMap、WeakSet
// 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;

// 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.Symbol


ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
var s1 = Symbol('foo');
var s2 = Symbol('bar');

s1 // Symbol(foo)
s2 // Symbol(bar)

s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"

s1===s2  //false

s3=Symbol.for('foo')
s4=Symbol.for('foo')
s3===s4  //true

Symbol.keyFor(s4)//foo

注意:Symbol对象不需要new来创建。
Symbol对象作为属性,不能使用.来访问
Symbol不能和其他数据类型进行计算
var mySymbol = Symbol();

// 第一种写法
var a = {};
a[mySymbol] = 'Hello!';

// 第二种写法
var a = {
  [mySymbol]: 'Hello!'
};

// 第三种写法
var a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });

// 以上写法都得到同样结果
a[mySymbol] // "Hello!"


11.Promise

Promise 是一个对象,从它可以获取异步操作的消息。
Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
//创建promise
var promise = new Promise(function(resolve, reject) {
    // 进行一些异步或耗时操作
    if ( /*如果成功 */ ) {
        resolve("Stuff worked!");
    } else {
        reject(Error("It broke"));
    }
});
//绑定处理程序
promise.then(function(result) {
	//promise成功的话会执行这里
    console.log(result); // "Stuff worked!"
}, function(err) {
	//promise失败会执行这里
    console.log(err); // Error: "It broke"
});


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值