javascript知识点(三)之 js下一代标准 ES6

ES6:ECMAScript 6.0是javascript语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得javascript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。各大浏览器的最新版本,随着时间的推移,支持度已经越来越多了,ES6的大部分特性都实现了。

1,let命令:用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

{
	var a = 1
	let b = 2
}
console.log(a)  //1
console.log(b)  //ReferenceError: b is not defined

    在代码块中定义的变量,在代码块外,var声明的变量返回了正确的值,let声明变量报错。

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

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

    上面代码中,变量i是var声明的,在全局范围内都有效。所以每一次循环,新的i值都会覆盖旧值,导致最后输出的是最后一轮的i的值。如果使用let,声明的变量仅在块级作用域内有效,最后输出的是6。变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。

不存在变量名提升

console.log(foo);//输出undefined
console.log(bar);//报错ReferenceError

var foo = 1;
var bar = 1;

        上面代码中,变量foo用var命令声明,会发生变量提升,即脚本开始运行时,变量foo已经存在了,但是没有值,所以会输出undefined。变量bar用let命令声明,不会发生变量提升。这表示在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误。

暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

var tmp = 123;

if(true){
	tmp = '123';//ReferenceError
	let tmp;
}

        上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。

        ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称TDZ)。

不允许重复定义

        let不允许在相同作用域内,重复声明同一个变量。重复声明会报错

块级作用域

        ES5只有全局作用域和函数作用域,let的出现实际上为JavaScript新增了块级作用域。

function f1 () {
	let n = 5;
	if(true) {
		let n = 10;
	}
	console.log(n)//5
}
2,const命令:声明一个只读常量,一旦声明常量值就不能改变

    const声明的变量不得改变值,const一旦声明变量 就必须立即初始化,不能留要以后赋值

    例如 const foo;//就会报错

    const命令和let命令很多相似:1,只在声明所在的块级作用域内有效。

                                                2,声明变量不提升。

                                                3,存在暂时性死区

                                                4,只能在声明位置后面使用

        对于复合类型(对象或者引用类型)的变量,变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个对象声明为常量必须非常小心。

const foo = {};
foo.prop = 123;

foo.prop //123

foo = {}//报错

        上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

3 ,顶层对象属性

    顶层对象,在浏览器环境指的是window对象,在Node指的是global对象。ES5之中,顶层对象的属性与全局变量是等价的。

window.a = 1;
a //1

a = 2;
window.a // 2

        顶层对象的属性赋值与全局变量的赋值,是同一件事。ES6为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。

var a = 1;

window.a //1

let b = 1;
window.b //undefined

4,变量的结构赋值

        ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为结构

var [a,b,c] = [1,2,3]
//可以从数组中提取值,按照对应位置,对变量赋值。
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  如果解构不成功,变量的值就等于undefined。
z //[]
//只要等号两边的模式相同,左边的变量就会被赋予对应的值。

 变量的结构赋值可以设置默认值

例如:var [foo = true] = [ ];   

          [x,y='b'] = ['a','undefined'] //x=a,y=b

        

对象的解构赋值:

var {foo,bar} = {foo:'aaa',bar:'bbb'};
foo //"aaa"
bar //"bbb"

//对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,
//变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

var {foo: baz} = { foo:"aaa",bar:'bbb'}

baz //"aaa"
foo //error
变量的解构赋值作用
//1,交换变量的值
[x,y] = [y,x];

//2,从函数返回多个值
//函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。
function example(){
	return [1,2,3];
}
var [a,b,c] = example()
//返回对象
function example(){
	return {
		foo:1,
		bar:2
	}
}
var {foo,bar} = example();

//3,函数参数的定义
function f([x,y,z]){}
f([1,2,3])

//4,提供JSON数据
var jsonData = {
	id:42,
	status:'ok',
	data:[867,5309]
}
let {id,status,data:number} = jsonData;

console.log(id,status,number);
//42,"ok",[867,5309]
5,字符串遍历器接口

ES6为字符串添加了遍历器接口,使得字符串可以被for...of循环遍历

for(let i of 'foo'){
	console.log(i)
}
//f
//o
//o
//includes():返回布尔值,表示是否找到了参数字符串。
//startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
//endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
var s = "hello world"

s.startsWith('hello') //true
s.endsWith('!') //true
s.includes('o') //true

第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。

6,repeat() 

repeat方法返回一个新字符串,表示将原字符串重复n次。


'x'.repeat(3) //"xxx"
'na'.repeat(2.9)//"nana"
//参数如果是小数,会被向下取整。
'na'.repeat(nan)//"参数NaN等同于0。"
'na'.repeat('3')//"nanana"
7,模板字符串
html = `<div class='box'>
	    <a href=""></a>
	</div>`
//如果使用模板字符串表示多行字符串,
//所有的空格和缩进都会被保留在输出之中。
8,箭头函数 
var f = v => v;
//上面的箭头函数等同于
var f = function(v){
	return v;
};

//如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var sum = (num1,num2) => num1 + num2;

var sum = function(num1,num2){
	return num1 +num2
}

//箭头函数的一个用处是简化回调函数,使得表达更加简介
[1,2,3].map(function(x){
	return x*x
})

//箭头函数写法
[1,2,3].map(x => x*x)
    注意:this对象的指向是可变的,但是在箭头函数中,它是固定的。
9,Set,类似于数组,但成员值都是唯一的,没有重复的值,set本身是一个构造函数,用来生成set数据结构
var s = new Set();

[1,2,3,2,3,4,1,5].map(x => s.add(x));

for(let i of s){
	console.log(i);
}
//1,2,3,4,5   //同时也有数组去重的方法
注意:set内部 NaN和NaN是相等的

    Set 实例的属性和方法

        constructor属性:构造函数,默认就是Set函数。

        size属性:返回Set实例的成员总数。

        Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)

        add(value):添加某个值,返回Set结构本身。

        delete(value):删除某个值,返回一个布尔值,表示删除是否成功。

        has(value):返回一个布尔值,表示该值是否为Set的成员。

        clear():清除所有成员,没有返回值。

        Array.from方法可以将Set结构转为数组。

keys(),values(),entries():keys方法、values方法、entries方法返回的都是遍历器对象

let set = new Set(['red','green','blue'])

for(let item of set.keys()){
	console.log(item);
}
//red
//green
//blue

for(let item of set.values()){
	console.log(item);
}
//red
//green
//blue

for(let item of set.entries()){
	console.log(item);
}
//['red','red']
//['green','green']
//['blue','blue']

10,Map,avaScript的对象(Object),本质上是键值对的集合,但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。为了解决这个问题,ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应。如果你需要“键值对”的数据结构,Map比Object更合适。
var map = new Map([
	['name','张三'],
	['title','Author']
])
map.size //2
map.has('name')//true
map.get('name')//'张三'

上面代码在新建Map实例时,就指定了两个键name和title。

注意,只有对同一个对象的引用,Map结构才将其视为同一个键。这一点要非常小心。

11, Map(字典)实例的属性和方法:

    size属性:返回Map结构的成员总数。

    set(key, value)set方法设置key所对应的键值,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。set方法返回的是Map本身,因此可以采用链式写法。

    和set实例很多相似处,就不一一列出,参考set、


12, Generator 生成器函数

        Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。从语法上,可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。形式上,Generator函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield语句,定义不同的内部状态(yield语句在英语里的意思就是“产出”)。

        执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历Generator函数内部的每一个状态。

13,class的写法
        ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用ES6的“类”改写,就是下面这样。
class point{
	constructor(x,y){
		this.x = x;
		this.y = y;
	}
	toString(){
		return '(' + this.x + ','+this.y +')';
	}
}
//上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,
//而this关键字则代表实例对象。也就是说,ES5的构造函数Point,对应ES6的Point类的构造方法。
//point类除了构造方法,还定义了一个toString方法。注意,定义“类”的方法的时候,
//前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。
//另外,方法之间不需要逗号分隔,加了会报错。

constructor方法:

            是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果 没 有显式定义,一个空的constructor方法会被默认添加。

类的继承:

            Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。


class colorPoint extends point{
	constructor(x,y,color){
		super(x,y);//调用父类的constructor(x,y)
		this.color = color
	}
	
	toString(){
		return this.color + ''+super.toString()//调用父类toString方法
	}
}

constructor方法和toString方法之中,都出现了super关键字,它在这里表示父类的构造函数,用来新建父类的this对象。

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。




猜你喜欢

转载自blog.csdn.net/hlyphard/article/details/79730101