资讯专栏INFORMATION COLUMN

ECMAScript6标准入门(一)新增变量与数据结构

Tangpj / 2199人阅读

摘要:一简介与的关系是的规格,是的一种实现另外的方言还有和转码器命令行环境安装直接运行代码命令将转换成命令浏览器环境加入,代码用环境安装,,根目录建立文件加载为的一个钩子设置完文件后,在应用入口加入若有使用,等全局对象及上方法安装

一、ECMAScript6 简介 (1) 与JavaScript的关系

ES是JS的规格,JS是ES的一种实现(另外的ECMAScript方言还有Jscript和ActionScript);

(2) Babel转码器 命令行环境

安装babel-cli, babel-preset-2015;

直接运行ES6代码:babel-node命令;

将ES6转换成ES5:babel命令;

浏览器环境

加入brower.js,ES6代码用type="text/babel"

Node.js环境

安装 babel-core,babel-preset-2015,根目录建立.babelrc文件:

{
    "preset":["es2015"]
}

(1) babel加载为require的一个钩子:设置完.babelrc文件后,在应用入口加入require("babel-core/register")

(2) 若有使用Iterator,Generator等全局对象及上方法:安装babel-polyfill模块,并在应用头部require("babel-polyfill")

二、变量 (1) let命令 基本用法

与var类似,但变量只在let的代码块内有效;

var a = [];
for (let i = 0; i < 10;i++) {
    a[i] =function () {
        console.log(i);
    };
}
a[6](); 
// 6,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,最后输出的是6;若用var i = 0,则将为10
注意:

(1) 无“变量提升”,用let声明的对象之前需要先声明再使用;

(2) 暂时性死区(Temporal Dead Zone),只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量;同时,也意味着:typeof操作不是绝对安全的!

// 2.暂时性死区 例子
var tmp = 123;
if (true) {
    tmp = "abc"; //ReferenceError
    let tmp;
}

typeof x; // ReferenceError
let x;

function bar(x = y, y = 2) {
    return [x, y];
}
bar(); // 报错

(3) 不允许重复声明,相同作用域中不能用var,let再次声明let变量(若不是相同作用域则无妨,即再嵌套一个{},花括号里外就是不同作用域)

(2) 块级作用域

可以在块级作用域中声明函数,且该行为类似于let:

function f() { console.log("I am outside!"); }
(function () {
    if(false) {
        //重复声明一次函数f
        function f() { console.log("I am inside!"); }
    }
    f();
}());

以上代码在不同的版本下会有差别:

ES5:运行结果“I am inside!”,相当于声明提前;

ES6:运行结果“I am outside!”,相当于里面的是块作用域,f() 用的是闭包里的;

ES6的浏览器:报错“f is not a function”,根据规则:函数声明会提前到全局、函数作用域的头部(类似var),也会提前到块级作用域的头部,相当于在只执行函数头部var f = undefined

(3) const命令

与let相同,块级作用域,但是常量需要初始化;

const声明对象时,其地址不可变,但其中内容可变;

(4) 全局对象的属性 与 全局变量

用ES5的命令var, function声明的变量依然是全局对象的属性,而用ES6命令声明的变量则不是

以上规则在Node的REPL中适用,模块环境下,则只能用global.a来调用全局变量;

三、变量的解构赋值 (1) 数组的解构

例子:

var [a, b, c] = [1, 2,3]; // 则abc分别为123
特殊情况

跳过:let [x, , y] = [1, 2, 3]; // y为3

数组:let [head, ...tail] = [1, 2, 3, 4]; // tail为[2,3,4]

左边解构不成功(左边多),则变量为undefined

右边不完全解构(左边少),则忽略右边;

右边为非可遍历,则报错;

默认值 undefined,[]

例子:(右边必须为=== undefined)

let [x, y, ...z] = ["a"];
x // "a"
y // undefined
z // []

注意:

惰性求值:若默认为函数,只有在解构用到默认值时才调用;

可以用已经声明的变量作为默认值,未声明的则报错

(2) 对象的解构

同名属性赋值,左边含义为{模式:变量},完整格式如:

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

若模式与变量同名则可以省略模式,否则必须完整

var { foo: baz } = { foo: "aaa", bar:"bbb" };// 变量baz为"aaa"

注意:

“变量”部分的重新声明(代码见后);

嵌套赋值(代码见后);

将已声明的变量用于解构赋值,需要加括号(代码见后);

// --------- 1. 变量部分重新声明 ---------
let foo;
let {foo} = {foo: 1}; // SyntaxError: Duplicate declaration "foo"
({foo} = {foo: 1}); // 成功

let baz;
let {bar: baz} = {bar: 1}; // SyntaxError: Duplicate declaration "baz"
({bar: baz} = {bar: 1});  // 成功

// --------- 2. 嵌套赋值 ---------
let obj = {};
let arr = [];

({ foo: obj.prop, bar: arr[0] } = { foo: 123,bar: true });
obj // {prop:123}
arr // [true]

// 以下报错
var {foo: {bar}} = {baz:"baz"}; // 因为foo为undefined,则foo.bar会报错

// --------- 3. 将已声明的变量用于解构赋值,需要注意 ---------
var x;
{x} = {x: 1};

// 正确的写法
({x} = {x: 1});
// 因为“{”在行首,会被理解为一个代码块,故而后面报错;
(3) 字符串、数值、布尔型解构

等式的右边会转换层包装对象,故而等式左边可以写成 length:s, toString: s;

(4) 函数参数的解构

例子:

function add([x, y]){
    returnx + y;
}
add([1, 2]); // 3

对比 设定参数对象默认值 与 对象解构的默认值 的区别

// 对象解构的默认值
function move({x = 0, y = 0} = {}) {
  return[x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0] 

// 参数对象的默认值
function move({x, y} = { x: 0, y: 0 }) {
  return[x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
(5) 解构中的圆括号

声明中不可使用圆括号,赋值语句中的非模式部分(变量与整体)可以使用圆括号

四、第七种数据类型——Symbol (1) 数组的解构

用途:保证对象属性名的唯一性;

生成方法:通过Symbol()函数,可传参数作为描述;

注意

不能在Symbol()函数前面加new,否则报错,因为Symbol不是对象;

Symbol()函数不能与其他类型的值进行运算,但可转成字符串或布尔值(true);

Symbol(s)中的参数仅仅用于toString()控制台输出作为人工区分,即使没有参数也是不同的变量;

var s1 = Symbol();
var s2 = Sy mbol();
s1 === s2 // false

(2) 作为属性名 (a) 方式
a[mySymbol] = "xx";
a = {
  [mySymbol] = "xx" //方括号不能去
};
Object.defineProperty(a, mySymbol, {
  value: "xx" 
});
(b) 注意

当Symbol作为属性名时,不能用点运算符,a.mySymbol其实为a["mySymbol"];

(c) 遍历

用Object.getOwnPropertySymbols(),返回数组,其成员是所有用作属性名的Symbol值;

Reflect.ownKeys(),返回自身所有类型的键名,包括Symbol值;

(3) Symbol的方法 (a) Symbol.for(s)

重新使用同一个Symbol,搜索有没有s为名字的Symbol,有就返回,无则新建Symbol;这是全局的,即使不同iframe也用同一个Symbol;

(b) Symbol.keyFor()

返回一个已用Symbol.for()登记的Symbol类型值的key;

(4) 对象中内置Symbol.xx属性

Symbol.hasInstance:指向内部方法,当其他对象使用instanceof运算符时,会调用这个方法;

Symbol.isConcatSpreadable:布尔值,表示使用concat()时,是展开成元素还是整个数组

Symbol.species:指向一个方法,当该对象作为构函创造实例时,调用该方法;

Symbol.match:指向一个方法,执行match()时会调用;

Symbol.replace:指向一个方法,执行replace()时会调用;

Symbol.search:指向一个方法,执行search()时会调用;

Symbol.split:指向一个方法,执行split()时会调用;

Symbol.iterator:指向该对象的默认遍历器;

Symbol.toPrimitive:指向一个方法,该对象被转为原始类型的值时调用,返回该对象对应的原始类型值;

Symbol.toStringTag:指向一个方法,调用toString()方法时,返回成[object xxx]

Symbol.unscopables:指向一个对象,指定了使用with关键字时,哪些属性被with排除;

五、Set与WeakSet (1) Set

集合,类似数组,成员值唯一;采用===,除了NaN

(a) 格式
new Set([array]) 
(b) 属性

Set.prototype.constructor:构造函数,默认就是Set函数;

Set.prototype.size:返回Set实例的成员总数;

(c) 方法

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

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

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

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

以下为遍历方法

keys():返回键名的遍历器,Set键名与键值相同;

values():返回键值的遍历器,Set键名与键值相同;

entries():返回键值对的遍历器;

forEach(func):使用回调函数遍历每个成员;

(2) WeakSet (a) 与Set的区别

元素只能是对象

其中的对象都是弱引用,垃圾回收机制不考虑其对象的引用,即若无其他对象引用该对象,则回收;

因无法引用该对象,故无法遍历

(b) 方法

WeakSet.prototype.add(value):向WeakSet实例添加一个新成员;

WeakSet.prototype.delete(value):清除WeakSet实例的指定成员;

WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在WeakSet实例之中;

六、Map与WeakMap (1) Map

类似对象,键值对的集合,但其键的范围不限于字符串;参数是数组,其成员是[[key1, value1], [key2, value2]]

(a) 注意

同一个键多次赋值,则会覆盖

读取未知的键,返回undefined;

对同一个对象的引用作为键,Map才视为同一个键,NaN、正负0分别视为同一个对象

map.set(["a"], 555);
map.get(["a"]);        //undefined 

var k1 = ["a"];
var k2 = ["a"];
map
.set(k1, 111)
.set(k2, 222);
map.get(k1) // 111
map.get(k2) // 222

(b) 属性与操作方法

size属性:返回成员总数;

set(key, value):设置key所对应的键值,然后返回整个Map结构,若已存在键,则更新值;

get(key):读取对应键值,无则返回undefined;

has(key):返回布尔值,表示是否在Map中;

delete(key):删除某个键,返回true,失败则false;

clear():清除所有成员,无返回;

遍历方法:keys(), values(), entries(), forEach();

(2) WeakMap

与Map结构类似,唯一区别在于只接受对象作为键名(null除外)

WeakMap的专用场合就是,它的键所对应的对象,可能会在将来消失,WeakMap结构有助于防止内存泄漏;

没有遍历操作,也没有size属性

无法清空

七、类class (1) 基本语法

class类型看成是函数,类本身就是指向构造函数;

类的方法都定义在prototype对象上面,所以类的新方法可以添加在prototype对象上面;

//定义类
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
 }  // 这里无分号

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

class表达式

const MyClass = class Me {...}
// 该类的名字是MyClass而不是Me,Me只在Class内部代码可用
(2) constructor方法

new命令生成对象实例时,调用该方法;

若无显式的,则默认添加一个空的constructor函数;

注意:无变量提升;

(3) 继承 (a) 基本用法
class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y), 必须要调用super()方法,因为子类需要用到父类的this
   this.color = color;
}

  toString() {
    return this.color + " " + super.toString(); // 调用父类的toString()
  }
}
(b) 原型属性

子类的__proto__属性,表示构造函数的继承,总是指向父类;

子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性;

(c) 继承的特殊情况

子类继承Object

A.proto === Object // true
A.prototype.proto === Object.prototype // true

不存在任何继承

A.proto === Function.prototype // true
A.prototype.proto === Object.prototype // true

子类继承null

A.proto === Function.prototype // true
A.prototype.proto === undefined // true
(d) 实例的__proto__属性

子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性,即子类的原型的原型,是父类的原型;

(4) 继承原生构造函数

ES5中,先创建子类this,父类的属性添加到子类上,由于父类内部属性无法获取,导致无法继承原生的构造函数;

ES6中,先新建父类this,然后再用子类构造函数修饰this,这使得父类的所有行为都可以继承;

(5) class的存取值函数
class MyClass {
 constructor() {
   // ...
  }
  get prop() {
      return "getter";
  }
  set prop(value) {
   console.log("setter: "+value);
  }
}
(6) Generator方法
class Foo {
  constructor(...args) {
    this.args = args;
  }
  *Symbol.iterator {
      for(let arg of this.args) {
        yield arg;
    }
  }
}
(7) 静态方法

在方法前加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用;

父类的静态方法,可以被子类继承,也可用super对象调用;

(8)(ES7)静态属性和实例属性

(ES6规定,只有静态方法,无静态属性,ES7草案有静态属性)

实例属性

class MyClass {
  myProp = 42;
  constructor() {
      console.log(this.myProp); // 42
  }
}

静态属性

class MyClass {
  static myStaticProp = 42;
  constructor() {
    console.log(MyClass.myProp); // 42
  }
}
(9) new.target属性

返回new命令作用于的那个构造函数,如果构造函数不是通过new命令调用的,new.target会返回undefined;

Class内部调用new.target,返回当前Class

子类继承父类时,new.target会返回子类

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87904.html

相关文章

  • 【前端】ES6入门基础知识

    摘要:关于的入门了解新增模板字符串为提供了简单的字符串插值功能箭头函数操作符左边为输入的参数,而右边则是进行的操作以及返回的值。将对象纳入规范,提供了原生的对象。增加了和命令,用来声明变量。 关于ES6的入门了解 新增模板字符串(为JavaScript提供了简单的字符串插值功能)、箭头函数(操作符左边为输入的参数,而右边则是进行的操作以及返回的值Inputs=>outputs。)、for-o...

    philadelphia 评论0 收藏0
  • Vue.js新手入门指南[转载]

    摘要:就是一个用于搭建类似于网页版知乎这种表单项繁多,且内容需要根据用户的操作进行修改的网页版应用。单页应用程序顾名思义,单页应用一般指的就是一个页面就是应用,当然也可以是一个子应用,比如说知乎的一个页面就可以视为一个子应用。 最近在逛各大网站,论坛,以及像SegmentFault等编程问答社区,发现Vue.js异常火爆,重复性的提问和内容也很多,楼主自己也趁着这个大前端的热潮,着手学习了一...

    MartinHan 评论0 收藏0
  • ES6学习摘要(01)(新人学习)

    摘要:入门一前言由于最近本人在学习,做一些笔记能够更好的熟悉,就趁此机会来写一篇关于的新人学习摘要吧。的作用域与命令相同只在声明所在的块级作用域内有效。块级作用域新增方式和实际上为新增了块级作用域。同时,函数声明还会提升到所在的块级作用域的头部。 ECMAScript6/ES6 入门 一、前言 由于最近本人在学习ES6,做一些笔记能够更好的熟悉,就趁此机会来写一篇关于ES6的新人学习摘要吧。...

    dmlllll 评论0 收藏0
  • ECMAScript6(3):数值类型扩展

    摘要:数值类型扩展类型新增了如下特性支持二进制和八进制二进制用或开头八进制用或开头新加方法判断一个数字是否有限方法判断一个变量是否。值得注意的是如果将非数值传入这两个函数一律返回。对于无法转换为数值的参数返回符合函数。 数值类型扩展 Number 类型新增了如下特性: 支持二进制和八进制 二进制用 0b 或 0B 开头, 八进制用 0o 或 0O 开头: Number(0b1101); ...

    Martin91 评论0 收藏0
  • ECMAScript6 新特性——“let和const命令”

    摘要:基本用法所声明的变量,只在命令所在的代码块内有效。在循环中适合使用不存在变量提升不像那样会发生变量提升现象暂时性死区只要块级作用域内存在命令,它所声明的变量就绑定这个区域,不再受外部的影响。块级作用域实际上为新增了块级作用域。 1 let 基本用法 所声明的变量,只在let命令所在的代码块内有效。 { let b = 100; console.log(b); //100...

    PascalXie 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<