es6语言特性的总结(1)

虽然在编写项目的过程中,也会用到ES6的语法以及新特性。但感觉学习的不是特别系统,索性这两天重新刷了一下Understanding The ES6,也对ES6有了更深的理解。这里,针对感觉应用比较多,知识点比较重要的部分做了一下总结。内容有点多,因此预计将分为三个部分。

块级绑定-作用域

在ES5中,有一个知识难点,就是变量提升和作用域。而这一部分之所以让人困扰,则是因为JS中变量的声明方式会影响变量实际的创建位置。

有一条规则是:使用var关键字声明的变量,无论其实际声明位置在何处,都会被声明与函数的顶部,这就是变量提升(hosting)。

ES6中为了让变量的生命周期更加可控,引入了块级声明。即,让所声明的变量在指定块的作用域外无法被访问。ES6主要引入了两个新的关键字,letconst

let

letvar类似,不同是的,let声明的变量不会存在变量提升的情况。因此,下面这个代码中:

{
  let a = 1;
}

console.log(a); 

是无法访问到a变量的。

另一个限制的地方是,禁止重复声明相同的变量。

var a = 1;
let a = 2;

上面的代码也会报错。

const

这个关键字也是限制了变量提升以及重复声明,而且变量值是不可更改的。

const a = 1;
a = 2; //报错

但是,如果绑定的是对象,可以更改对象属性值。

const person = { 'name': 'xiaoming', 'age': 12};
person.name = 'zhangsan';
console.log(person.name); //zhangsan

暂时性死区

利用letconst声明的变量,代码在访问到声明处前都是禁止访问的。

let a = 2;
a = b; // b is not defined
let b = 3;

循环中的let和const声明

请看下面这段代码:

var array = [];

for(var i = 0 ; i < 10; i++) {
    array.push(function() {
      console.log(i);
    });
}

array.forEach(function(func) { func(); }); //会输出10次10

使用var声明的变量,会在每次循环中被共享了。因此,在循环内部创建的函数都用于同一个变量的引用。通常解决这种方式,在ES5中会采用闭包的方式。而ES6中,可以使用let关键字

var array = [];

for(let i = 0 ; i < 10; i++) {
    array.push(function() {
      console.log(i);
    });
}

array.forEach(function(func) { func(); }); //会依次输出0...9

这是因为let关键字在每次循环中,都会创建一个新的i变量,而循环内部的函数获取的i变量其实都是副本。

const关键字不可以用在传统的for循环中,但是可以用在for...offor … in语法中。使用效果和let一样。

函数

ES6中对函数的功能做了新的扩展,使之使用起来更方便。

箭头函数

自从有了箭头函数,在遇到回调函数写法的时候,就特别方便。当然它的功能肯定不止于此。箭头函数的语法像这样:

(变量名,[其他变量名]) => { //函数体} 
//有以下几种变形
(value1, value2) => {return value1 + value2;} 
(value1, value2) => value1 + value2; //函数体只有一条return语句的时候,可以省略return关键字和{}
value => value1 + 1; //单参数函数时候,可以省略括号

是传统函数写法的一种便捷写法,同时,有以下几个特点:

  1. 不允许重复的具名参数
  2. 没有arguments对象
  3. 不能更改this,在整个函数声明周期内其值会保持不变,因此,在遇到this问题时,不用再像ES5之前的时期使用类似var self =thisbind(this)之类的方法了。
  4. 不能被new调用
  5. 没有this、super、arguments、也没有new.target绑定

默认参数和不具名参数

先看下面这个例子,同时使用了默认参数和不具名参数(也叫做剩余参数):

//num1如果不传值或者为undefined的话为0, num2是一个数组代表后续传进来的参数集合
function add(num1 = 0, ...num2) {
    num2.forEach(i => num1 = num1 + i);
    return num1;
}

console.log(add(undefined,2)); //2

console.log(add(undefined,2,3)); //5

console.log(add(1,2,3)); //6

采用了默认参数值时,仍然可以使用arguments对象来反应真实函数的调用状态, 而arguments对象也可以和不具名参数进行协同工作。

function add(num1 = 1, num2 = 1) {
    console.log(arguments);
}

add(1); //[1]
add(2, 3); //[2,3]
add(); //[]
add(2,3,4,5,6); //[2,3,4,5,6]

同时,函数的默认值甚至可以利用函数来动态生成,而非写死的,如:

function getNum() {
  return parseInt(Math.random() * 10);
}

function add(num1 = getNum(), num2 = 1) {
  console.log(num1 + num2);
}

//每次调用的结果是随机的,以下为某一次调用的结果
add(); // 8
add(); // 4

需要注意的是,函数的不具名参数是不能够在对象的setter上使用的,这是因为setter只接受单一值作为它的参数。

扩展运算符

这三个点运算符用在函数声明的时候,就是不具名参数,但是它同时也能用在解构对象上,因此,在函数调用过程中,可以使用该运算符,进行多个参数传递。如

var randomArray = [2,3,1231,455,231,23,553];
console.log(Math.max(...randomArray)); //1231

new.target

这是ES6函数对象的元属性,可以通过检查new.target对象是否被定义,可以判断函数是否通过new进行调用。

function Cat() {
  if(new.target === undefined) {
    console.log('this is not called by NEW keyword');
  }else {
    console.log('this is called by NEW keyword');
  }
}

new Cat(); //this is called by NEW keyword
Cat.call(this); //this is not called by NEW keyword

原理方面,其实就是当函数的构造器(constructor)方法被调用时,new.target 会被填入 new 运算符的作用目标,该目标通常是新创建的对象实例的构造器,并且会成为函数体内部的 this 值。而若call方法被执行的时候, new.target 的值则会是undefined

解构

解构的意思是将数据结构分解为更小的部分,而ES6中引入了解构的方式目的就是能够更好地提取数据。

对象解构

直接上例子:

let { type, name } = node //普通解构
let { type, name, value = true } = node; //默认值解构
let { type: localType, name: localName } = node; //赋值给不同的本地对象
let { loc: { start: localStart }} = node; //嵌套的解构方式,等同于localStart = node.loc.start

以上需要注意的是,当解构赋值表达式的右侧( = 后面的表达式)的计算结果为 null 或 undefined 时,会抛出错误。

数组解构

数组解构时,解构作用在数组内部的位置上,而不是作用在对象的具名属性上。

let [ , , thirdColor ] = colors;

let [ firstColor, secondColor = "green" ] = colors; //默认值

let [ firstColor, [ secondColor ] ] = colors; //嵌套解构

let [ firstColor, ...restColors ] = colors; //剩余项

[a, b] = [b, a]; //数组解构赋值有一个非常独特的用例,能轻易地互换两个变量的值

参数解构

function doSomething(value1, value2, {value3, value4, value5}) {

}

需要注意的是默认情况下调用函数时未给参数解构传值会抛出错误。但若你要求它是可选的,可以给解构的参数提供默认值来处理这种行为。

function dosomething(value1, value2, {value3, value4, value5} = {}) {
  //dosomething
}

扩展的对象功能

在ES6中也对对象的使用方式做了进一步的扩展,使其无论是在代码编写形式层面还是底层操作对象的层面都有了更多的特性。

对象类别

在ES6规范中,定义了对象的每种类别:

1.普通对象:拥有JS对象所有默认的内部行为

2.奇异对象:有别于默认的内部行为的对象

3.标准对象:是在ES6中被定义的对象,可以是普通对象也可以是奇异对象。

4.内置对象:在脚本开始运行时由JS运行环境(浏览器或Node)提供的对象。所有标准对象都是内置对象。

属性初始化器

当对象的一个属性名称与本地变量名相同的时候,可以省略冒号和值,如:

function createPerson(name, age) {
  return {
    name,
    age
  }
}
//等同于
function createPerson(name, age) {
    return {
      name: name,
      age: age
    }
}

方法简写

方法简写如下:

var person = {
  name: 'nihao',
  getName() {
    return this.name;
  }
}

//等同与
var person = {
  name: 'nihao',
  getName: function() {
    return this.name;
  }
}

需要注意的是,使用方法简写,在方法内部可以使用super方法,而传统的写法是无法使用的。

计算性属性名

属性名可以使用拼接的写法,如:

var name = 'name';

var person = {
  ['first' + name]: 'scq',
  ['last' + name]: '000',
  getName() {
    return this.firstname + this.lastname;
  }
}

对于某些需要动态生成属性名的场合,写法更加方便。

Object.is方法

为了避免在对象比较过程中的强制对象转换。通常该方法的运行结果和===一样,但是+0-0,NaNNaN不相同。

Object.assign(source, target) 方法

该方法接受一个接收者,以及任意数量的供应者,并会返回接收者。我通常在使用的时候,用来做继承或者说深度拷贝??。

    const person = {
      name: 'scq000',
      age: 23,
      addressInfo: {
        city: 'zs',
        address: 'some address'
      }
    }
    const person2 = Object.assign({}, person);

Object.assign() 方法接受任意数量的供应者,而接收者会按照供应者在参数中的顺序来依次接收它们的属性。这意味着在接收者中,第二个供应者的属性可能会覆盖第一个供应者的。

关于重复的对象字面量属性

ES6 移除了重复属性的检查,严格模式与非严格模式都不再检查重复的属性。当存在重复属性时,排在后面的属性的值会成为该属性的实际值。

自有属性的枚举顺序

1.所有的数字类型键,按升序排列。

2.所有的字符串类型键,按被添加到对象的顺序排列。

3.所有的符号类型键,也按添加顺序排列。

修改对象的原型

对象原型的实际值被存储在一个内部属性[[Prototype]] 上, Object.getPrototypeOf() 方法会返回此属性存储的值,而 Object.setPrototypeOf() 方法则能够修改该值。ES6 通过添加 Object.setPrototypeOf()方法而改变了这种假定,此方法允许你修改任意指定对象的原型。它接受两个参数:需要被修改原型的对象,以及将会成为前者原型的对象。
因为这个特性的添加,可以使用 super 进行简单的原型访问。super 是指向当前对象的原型的一个指针,实际上就是 Object.getPrototypeOf(this) 的值。这个功能在使用ES6类的继承的时候,提供了更好的访问父类的方式。

class Animal {
  constructor(name, size) {
    this.name = name;
    this.size = size;
  }
}

class Cat  extends Animal {
  constructor(size) {
    super('cat', size);
  }
}

系列二
系列三

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 一、ES6简介 ​ 历时将近6年的时间来制定的新 ECMAScript 标准 ECMAScript 6(亦称 ...
    一岁一枯荣_阅读 6,065评论 8 25
  • 函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。 上面代码检查函数l...
    呼呼哥阅读 3,363评论 0 1
  • 三,字符串扩展 3.1 Unicode表示法 ES6 做出了改进,只要将码点放入大括号,就能正确解读该字符。有了这...
    eastbaby阅读 1,521评论 0 8
  • 特别说明,为便于查阅,文章转自https://github.com/getify/You-Dont-Know-JS...
    杀破狼real阅读 565评论 0 0
  • 第一步,线稿。 第二步,画两朵。 第三步,画三朵。 第四步,画枝干和花苞。 第五步,画小贴纸,完成。 深夜来相会的...
    和尘之尘阅读 590评论 3 12