ES6新语法快速入门学习教程

来源:互联网 发布:apache ab 中文参数 编辑:程序博客网 时间:2024/06/06 07:25

什么是ES6?

 

ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在20156月正式发布了。

ECMAScriptJavaScript到底是什么关系?很多初学者会感到困惑,简单来说,ECMAScriptJavaScript语言的国际标准,JavaScriptECMAScript的实现。

199611月,JavaScript的创造者Netscape公司,决定将JavaScript提交给国际标准化组织ECMA,希望这种语言能够成为国际标准。次年,ECMA发布262号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为ECMAScript。这个版本就是ECMAScript 1.0版。

ES6的目标,是使得JavaScript语言可以用来编写大型的复杂的应用程序,成为企业级开发语言。

 

支持ES6的浏览器:

 

 虽说ES6已经作为新一代标准发布了,但是各大浏览器对新功能实现支持的还需要一段时间,那么我们怎么知道自己使用的浏览器是否支持ES6的相应功能呢?

  不用紧张,对ES6的支持可以查看kangax.github.io/es5-compat-table/es6/,在这里可以清晰的了解到不同版本的浏览器对ES6功能的支持情况。随着时间的推移,支持度已经越来越高了,ES6的大部分特性都实现了。

  如果你想现在就在浏览器使用ES6的特性,还可以通过引用兼容包的方式提前尝尝鲜。 https://github.com/paulmillr/es6-shim

环境支持:babel

 

直接插入网页

Traceur允许将ES6代码直接插入网页。首先,必须在网页头部加载Traceur库文件。

 

<!-- 加载Traceur编译器 -->

<script src="http://google.github.io/traceur-compiler/bin/traceur.js"

        type="text/javascript"></script>

<!-- 将Traceur编译器用于网页 -->

<scripttype="text/javascript">

new traceur.WebPageTranscoder(document.location.href).run();

</script>

<!-- 打开实验选项,否则有些特性可能编译不成功 -->

<script>                                           

        traceur.options.experimental = true;

</script>

 

<script type="module">

  class Calc {

    constructor(){

      console.log('Calc constructor');

    }

    add(a, b){

      return a + b;

    }

  }

 

  var c = new Calc();

  console.log(c.add(4,5));

</script>

注意,script标签的type属性的值是module(或者traceur),而不是text/javascript。这是Traceur编译器识别ES6代码的标识,编译器会自动将所有type=module的代码编译为ES5,然后再交给浏览器执行。

 

 

 

let

 

letES6中新增关键字。

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

if(true){

    var a = 1;

    let b = 2;

}

document.write(a);

document.write(b);  // 报错:ReferenceError: b is not defined

体会下letvar的作用域范围:

 

function f1() {

  var a = 8;

  let n = 5;

  if (true) {

      let n = 10;

      var a = 20

  }

  document.write(n); // 5

  document.write(a); // 20

}

f1();

const命令

 

const 声明的是常量,一旦声明,值将是不可变的。

 

const PI = 3.1415;

console.log(PI);

PI = 3;

console.log(PI);

const 也具有块级作用域

 

if (true) {

  const max = 5;

}

document.write(max);  // ReferenceError 常量MAX在此处不可得

 

const 不可重复声明

var message = "Hello!";

let age = 25;

 

// 以下两行都会报错

const message = "Goodbye!";

const age = 30;

 

是否包含字符串三种新方法

传统上,JavaScript只有 indexOf 方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6又提供了三种新方法。

  • includes():返回布尔值,表示是否找到了参数字符串。
  • startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
  • endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。

 

 

var str = "Hello world!";

str.startsWith("Hello") // true

str.endsWith("!") // true

str.includes("o") // true

 

这三个方法都支持第二个参数,表示开始搜索的位置。

 

var str = "Hello world!";

str.startsWith("world", 6) // true

str.endsWith("Hello", 5) // true

str.includes("Hello", 6) // false

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

 

 

repeat()原字符串重复

 

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

 

var str = "x";

str.repeat(3) // "xxx"

 

var str1 = "hello";

str1.repeat(2) // "hellohello"

 

 

模板字符串

模板字符串提供了3个有意思的特性。

模板字符中,支持字符串插值:



let first = '我叫xxx';

let last = '我是搬砖工';

document.write(`Hello ${first} ${last}!`);   //注意引号

 

模板字符串可以包含多行:

 

let multiLine = `

    This is

    a string

    with multiple

    lines`;

    document.write(multiLine); 

 

 

 

 

Array.from()

 

Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-likeobject)和可遍历(iterable)的对象(包括ES6新增的数据结构SetMap)。

下面是一个类似数组的对象,Array.from将它转为真正的数组。

       let array = Array.from({ 0: "a", 1: "b", 2: "c", length: 3 });

document.write(array);    // [ "a", "b" , "c" ]

 

 

    let arrayLike = {

                                '0': 'a',

                                '1': 'b',

                                '2': 'c',

                                length: 3

                            };

 

// ES5的写法    这句话相当于Array.prototype.slice.call(arrayLike)

 

//目的是将arrayLike对象的数组提出来转化为数组,arrayLike本身并不是数组而是对象

 

var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']

 

                            console.log(arr1);

 

                            // ES6的写法

                            let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

 

                            console.log(arr2);

 

Array.from()还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理。

 

 

let array = [0,1,2,3,4];

let arrNew = Array.from(array, x => x * x);

console.log(arrNew);

// 等同于

let arrNew = Array.from(array).map(x => x * x);

 

 

Array.of()

 

Array.of方法用于将一组值,转换为数组。

Array.of(3, 11, 8) // [3,11,8]

Array.of(3) // [3]

Array.of(3).length // 1

 

数组实例的find()和findIndex()

数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined

 

 

let array = [1, 4, -5, 10].find((n) => n < 0);

document.write("array:", array);

 

//上面代码找出数组中第一个小于0的成员。

 

 

//下面代码中 find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组

         let array = [1, 5, 10, 15].find(function(value, index, arr) {

                   return value > 9;

         })

         document.write(array);  // 10

 

 

 数组实例的findIndex方法,用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1

 

 

 

let index = [1, 5, 10, 15].findIndex(function(value, index, arr) {

  return value > 9;

})

document.write(index);  // 2

 

fill()填充数组 (了解)

 

fill()使用给定值,填充一个数组。

 

let arr = ['a', 'b', 'c'].fill(7)

document.write(arr);  // [7, 7, 7]

let newArr = new Array(3).fill(7)

document.write(newArr);  // [7, 7, 7]

上面代码表明,fill方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去。

fill()还可以接受第二个和第三个参数,用于指定填充的起始位置结束位置

 

let newArr = ['a', 'b', 'c'].fill(7, 1, 2)

document.write(newArr);   // ['a', 7, 'c']


entries()  keys()   values() -ES6提供三个新的方法

 

ES6提供三个新的方法:

         entries()

         keys()

         values()

用于遍历数组。它们都返回一个遍历器,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

for (let index of ['a', 'b'].keys()) {

  document.write(index);

}

// 0

// 1

 

for (let elem of ['a', 'b'].values()) {

  document.write(elem);

}

// 'a'

// 'b'

 

for (let [index, elem] of ['a', 'b'].entries()) {

  document.write(index, elem);

}

// 0 "a"

// 1 "b"

 


Es6对象的扩展

 

 

属性的简洁表示法

ES6允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

var foo = 'bar';

var baz = {foo};

baz // {foo: "bar"}

// 等同于

var baz = {foo: foo};

上面代码表明,ES6允许在对象之中,直接写变量。这时,属性名为变量名,属性值为变量的值。下面是另一个例子。

function f(x, y) {

  return {x, y};

}

// 等同于

function f(x, y) {

  return {x: x, y: y};

}

f(1, 2) // Object {x: 1, y: 2}

 

方法的简洁表示法

var o = {

  method() {   //es6 方法的简写

    return "Hello!";

  }

};

console.log(o);

// 等同于

var o = {

  method: function() {

    return "Hello!";

  }

};

console.log(o);

属性结合方法简写的例子:

var birth = '2000/01/01';

                     var Person = {

                       name: '张三',

                       //等同于birth: birth

                       birth,

                       // 等同于hello: function ()...

                       hello() { console.log('我的名字是', this.name); }

                     };

 

属性名表达式

JavaScript语言定义对象的属性,有两种方法

// 方法一

let obj = {};

obj.foo = true;

// 方法二

obj['a'+'bc'] = 123;

console.log(obj);

 

上面代码的方法一是直接用标识符作为属性名,方法二是用表达式作为属性名,这时要将表达式放在方括号之内。

如果使用字面量方式定义对象(使用大括号),在ES5中只能使用方法一(标识符)定义属性。

var obj = {

  foo: true,

  abc: 123

};

ES6允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。

let propKey = 'foo';

 let obj = {

   [propKey]: true,

   ['a'+'bc']: 123

};

表达式还可以用于定义方法名。

 

let obj = {

  ['h'+'ello']() {

    return 'hi';

  }

};

document.write(obj.hello()); // hi

 

Object.is()比较两个值是否严格相等

 

Object.is()用来比较两个值是否严格相等。它与严格比较运算符(===)的行为基本一致,不同之处只有两个:一是+0不等于-0,二是NaN等于自身。

 

 

+0 === -0 //true

NaN === NaN // false

 

Object.is(+0, -0) // false

Object.is(NaN, NaN) // true

 

 

 

Object.assign()源对象的所有可枚举属性,复制到目标对象

Object.assign方法用来将源对象(source)的所有可枚举属性,复制到目标对象(target)。它至少需要两个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出TypeError错误。

 

 

var target = { a: 1 };

 var source1 = { b: 2 };

var source2 = { c: 3 };

 Object.assign(target, source1, source2);

target // {a:1, b:2, c:3}

注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

vartarget = { a: 1, b: 1 };

 var source1 = { b: 2, c: 2 };

varsource2 = { c: 3 };

 Object.assign(target, source1, source2);

target// {a:1, b:2, c:3}

 

 

Object.assign方法有很多用处。

1)为对象添加属性

2)为对象添加方法

3)克隆对象

4)合并多个对象

 

 



ES6函数的扩展

 

默认参数

现在可以在定义函数的时候指定参数的默认值了,而不用像以前那样通过逻辑或操作符来达到目的了。

              //运用ES6的默认参数

              function sayHello(name){

                  //传统的指定默认参数的方式

                  var name = name|| 'qianfeng';

                  document.write('Hello '+name);

              }

             

              //运用ES6的默认参数

              function sayHello2(name='qianfeng'){

                  document.write(`Hello ${name}`);  /*注意引号*/

              }

              sayHello();  //输出:Hello qianfeng

              sayHello('我是代码搬砖工');  //输出:Hello我是代码搬砖工

              sayHello2();  //输出:Hello我是代码搬砖工

              sayHello2('我是代码搬砖工');  //输出:Hello我是代码搬砖工

rest参数(形式为“...变量名”)可以称为不定参数

rest参数(形式为...变量名)可以称为不定参数,用于获取函数的多余参数,这样就不需要使用arguments对象了。

rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

function add(...values) {

   let sum = 0;

   for (var val of values) {

      sum += val;

   }

   return sum;

}

add(1, 2, 3) // 6

不定参数的格式是三个句点后跟代表所有不定参数的变量名。比如以上示例中,...values 代表了所有传入add函数的参数。

扩展运算符

扩展运算符(spread是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。该运算符主要用于函数调用

它允许传递数组或者类数组直接做为函数的参数而不用通过apply

 

var people=['张三','李四','王五'];

//sayHello函数本来接收三个单独的参数people1people2people3

function sayHello(people1,people2,people3){

    document.write(`Hello ${people1},${people2},${people3}`);

}

//但是我们将一个数组以拓展参数的形式传递,它能很好地映射到每个单独的参数

sayHello(...people);   //输出:Hello张三,李四,王五

//而在以前,如果需要传递数组当参数,我们需要使用函数的apply方法

sayHello.apply(null,people);   //输出:Hello张三,李四,王五

 

 

// ES5
[1,2].concat(more)
// ES6
[1,2,...more]
 
var arr1 =['a','b'];
var arr2 =['c'];
var arr3 =['d','e'];
 
// ES5的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
 
// ES6的合并数组
[...arr1,...arr2,...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

 

 

箭头函数

箭头函数是使用=>语法的函数简写形式。这在语法上与 C#Java8 CoffeeScript 的相关特性非常相似。

var array = [1, 2, 3];

    //传统写法

    array.forEach(function(v, i, a) {

      document.write(v);

});

//ES6

array.forEach(v => document.write(v));

 

注意:它们同时支持表达式体和语句体。与(普通的)函数所不同的是,箭头函数和其上下文中的代码共享同一个具有词法作用域的this

 

var evens = [1,2,3,4,5];

        var fives = [];

        // 表达式体

        var odds = evens.map(v => v + 1);

        var nums = evens.map((v, i) => v + i);

        var pairs = evens.map(v => ({even: v, odd: v + 1}));

       

        // 语句体

        nums.forEach(v => {

          if (v % 5 === 0)

            fives.push(v);

        });

       

        document.write(fives);

       

        // 具有词法作用域的 this

        var bob = {

          _name: "Bob",

          _friends: ["Amy", "Bob", "Cinne", "Dylan", "Ellen"],

          printFriends() {

            this._friends.forEach(f =>

              document.write(this._name + " knows " + f));

          }

        }

       

        bob.printFriends();

 

函数绑定

函数绑定运算符是并排的两个双引号(::),双引号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。

let log = ::console.log;

// 等同于

var log = console.log.bind(console);

foo::bar;

// 等同于

bar.call(foo);

foo::bar(...arguments);

i// 等同于

bar.apply(foo, arguments);

 

 

 

ES6 SET  WeakSet

SET基本用法

数据结构Set类似于数组,但是成员的值都是唯一的,没有重复的值。

var s = new Set();

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

for (let i of s) {

  console.log(i);

}

Set函数可以接受一个数组作为参数,用来初始化

var items = new Set([1,2,3,4,5,5,5,5]);

document.write(items.size); // 5

 

 

SET实例属性和方法

Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。

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

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

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

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

 

 

 

 

 

s.add(1).add(2).add(2);

// 注意2被加入了两次

s.size // 2

s.has(1) // true

s.has(2) // true

s.has(3) // false

s.delete(2);

s.has(2) // false

下面是一个对比,看看在判断是否包括一个键上面,Object结构和Set结构的写法不同。

 

// 对象的写法

var properties = {

  'width': 1,

  'height': 1

};

if (properties[someName]) {

  // do something

}

// Set的写法

var properties = new Set();

properties.add('width');

properties.add('height');

if (properties.has(someName)) {

  // do something

}

SET遍历操作

Set结构的实例有四个遍历方法,可以用于遍历成员。

  • keys():返回一个键名的遍历器
  • values():返回一个键值的遍历器
  • entries():返回一个键值对的遍历器
  • forEach():使用回调函数遍历每个成员

由于Set结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。

 

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

for ( let item of set.keys() ){

  document.write(item);

}

// red

// green

// blue

 for ( let item of set.values() ){

  document.write(item);

}

// red

// green

// blue

for ( let item of set.entries() ){

  document.write(item);

}

// ["red", "red"]

// ["green", "green"]

// ["blue", "blue"]

set.forEach(function(item){

    document.write(item);

})

WeakSetSet一样都不存储重复的元素,但有一些不同点

WeakSet的成员只能是对象,而不能是其他类型的值。

var ws = new WeakSet();

ws.add(1)

// TypeError: Invalid value used in weak set

 

WeakSet结构有以下三个方法。

  • WeakSet.prototype.add(value):向WeakSet实例添加一个新成员。
  • WeakSet.prototype.delete(value):清除WeakSet实例的指定成员。
  • WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在

var ws = new WeakSet();

var obj = {};

var foo = {};

ws.add(window);

ws.add(obj);

ws.has(window); // true

ws.has(foo);    // false

 ws.delete(window);

ws.has(window);    // false

 

 

ES6函数的 map

 

Map结构的目的和基本用法

 

Map 是一个超对象,其 key 除了可以是 String类型之外,还可以为其他类型(如:对象)

 

var m = new Map();

 

o = {p: "Hello World"};

 

m.set(o, "content")

 

document.write(m.get(o))

// "content"

 

 

他的方法和 Set差不多:

  • size:返回成员总数。
  • set(key, value):设置一个键值对。
  • get(key):读取一个键。
  • has(key):返回一个布尔值,表示某个键是否在Map数据结构中。
  • delete(key):删除某个键。
  • clear():清除所有成员。
  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。

实例的属性和操作方法

Map结构的实例有以下属性和操作方法。

  • size:返回成员总数。
  • set(key, value):设置key所对应的键值,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。
  • get(key):读取key对应的键值,如果找不到key,返回undefined
  • has(key):返回一个布尔值,表示某个键是否在Map数据结构中。
  • delete(key):删除某个键,返回true。如果删除失败,返回false。
  • clear():清除所有成员,没有返回值。

set()方法返回的是Map本身,因此可以采用链式写法

let map = new Map()

  .set(1, 'a')

  .set(2, 'b')

  .set(3, 'c');

  document.write(map);

 

下面是has()delete()的例子。

var m = new Map();

 

m.set("edition", 6)        // 键是字符串

m.set(262, "standard")     // 键是数值

m.set(undefined, "nah")    // 键是undefined

 

var hello = function() {document.write("hello");}

m.set(hello, "Hello ES6!") // 键是函数

 

m.has("edition")     // true

m.has("years")       // false

m.has(262)           // true

m.has(undefined)     // true

m.has(hello)         // true

 

m.delete(undefined)

m.has(undefined)       // false

 

m.get(hello)  // Hello ES6!

m.get("edition")  // 6

 

下面是size属性和clear方法的例子。

 

let map = new Map();

map.set('foo', true);

map.set('bar', false);

 

map.size // 2

map.clear()

map.size // 0

遍历方法

 

Map原生提供三个遍历器。

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。

使用示例:

let map = new Map([

  ['F', 'no'],

  ['T',  'yes'],

]);

 

for (let key of map.keys()) {

  document.write(key);

}

// "F"

// "T"

 

for (let value of map.values()) {

  document.write(value);

}

// "no"

// "yes"

 

for (let item of map.entries()) {

  document.write(item[0], item[1]);

}

// "F""no"

// "T""yes"

 

// 或者

for (let [key, value] of map.entries()) {

  document.write(key, value);

}

 

// 等同于使用map.entries()

for (let [key, value] of map) {

  document.write(key, value);

}

Map结构转为数组结构,比较快速的方法是结合使用扩展运算符(...)。

 

let map = new Map([

  [1, 'one'],

  [2, 'two'],

  [3, 'three'],

]);

[...map.keys()]

// [1, 2, 3]

[...map.values()]

// ['one', 'two', 'three']

[...map.entries()]

// [[1,'one'], [2, 'two'], [3, 'three']]

[...map]

// [[1,'one'], [2, 'two'], [3, 'three']]

此外,Map还有一个forEach方法,与数组的forEach方法类似,也可以实现遍历。

 

map.forEach(function(value, key, map)) {

  document.write("Key: %s, Value: %s", key, value);

};

WeakMap

 

WeakMap结构与Map结构基本类似,唯一的区别是它只接受对象作为键名(null除外),不接受原始类型的值作为键名,而且键名所指向的对象,不计入垃圾回收机制。set()get()分别用来添加数据和获取数据:

 

var map = new WeakMap(),

    element = document.querySelector(".element");

 

map.set(element, "Original");

 

// 下面就可以使用了

var value = map.get(element);

document.write(value);             // "Original"

 

WeakMap与Map在API上的区别主要是两个:

·        一是没有遍历操作(即没有key()、values()和entries()方法),也没有size属性;

·        二是无法清空,即不支持clear方法。这与WeakMap的键不被计入引用、被垃圾回收机制忽略有关。

因此,WeakMap只有四个方法可用:get()set()has()delete()



ES6  Class

 

ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

 

//定义类

class Point {

  constructor(x, y) {

    this.x = x;

    this.y = y;

  }

  toString() {

    return '('+this.x+', '+this.y+')';

  }

}

上面代码定义了一个,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。

constructor方法

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。

 

实例对象

1.   var point=newPoint(2,3);

name属性

1.   classPoint{}

2.   Point.name//"Point"

class表达式

与函数一样,Class也可以使用表达式的形式定义。

const MyClass = class Me {

           getClassName() {

                   return Me.name;

           }

};

 

 

         var c = new MyClass();

 

console.log(c.getClassName());

Class的继承

 

Class之间可以通过extends关键字,实现继承。

子类会继承父类的属性和方法。

class Point {

                              constructor(x, y) {

                                this.x = x;

                                this.y = y;

                              }

                            }

                             

                            class ColorPoint extends Point {

                              constructor(x, y, color) {

                              //  this.color = color; // ReferenceError

                                super(x, y);    //

                                this.color = color; // 正确

                              }             /*注意方法之家没有分号*/

                              getData(){

                                   // console.log('123');

                                    console.log(this.x+'--'+this.y+'--'+this.color);

                                    return this.x+'--'+this.y+'--'+this.color;

                              }

                            }

 

 

                            let cp = new ColorPoint(25, 8, 'green');

 

                            cp.getData();

 

                            console.log(cp instanceof ColorPoint); // true

                            console.log(cp instanceof Point); // true

//instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype属性。

上面代码中,子类的constructor方法没有调用super之前,就使用this关键字,结果报错,而放在super方法之后就是正确的。

注意:ColorPoint继承了父类Point,但是它的构造函数必须调用super方法。

Class的静态方法

 

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为静态方法

 

class Foo {

  static classMethod() {

    return 'hello';

  }

}

Foo.classMethod() // 'hello'

var foo = new Foo();

foo.classMethod()

// TypeError: undefined is not a function

上面代码中,Foo类的classMethod方法前有static关键字,表明该方法是一个静态方法,可以直接在Foo类上调用(Foo.classMethod()),而不是在Foo类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。

父类的静态方法,可以被子类继承。

 

class Foo {

  static classMethod() {

    return 'hello';

  }

}

class Bar extends Foo {

}

Bar.classMethod(); // 'hello'

上面代码中,父类Foo有一个静态方法,子类Bar可以调用这个方法。

静态方法也是可以从super对象上调用的。

class Foo {

  static classMethod() {

    return 'hello';

  }

}

class Bar extends Foo {

  static classMethod() {

    return super.classMethod() + ', too';

  }

}

Bar.classMethod();

 

 

 

ES6  模块

export命令

 

模块功能主要由两个命令构成:exportimport

  • export命令用于用户自定义模块,规定对外接口;
  • import命令用于输入其他模块提供的功能,同时创造命名空间(namespace),防止函数名冲突。

ES6允许将独立的JS文件作为模块,允许一个JavaScript脚本文件调用另一个脚本文件。

现有profile.js文件,保存了用户信息。ES6将其视为一个模块,里面用export命令对外部输出了三个变量。

// profile.js

var firstName = 'Michael';

var lastName = 'Jackson';

var year = 1958;

 

export {firstName, lastName, year};

 

 

import命令就用于加载profile.js文件,并从中输入变量。import命令接受一个对象(用大括号表示),里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。

如果想为输入的变量重新取一个名字,import语句中要使用as关键字,将输入的变量重命名。

 

import { lastName as surname } from './profile';

 

注意:浏览器测试为:

 

import {firstName, lastName, year} from './module/profile.js';

console.log(firstName);

 

export default命令

 

为加载模块指定默认输出,使用export default命令。

 

// export-default.js

export default function () {

  document.write('foo');

}

上面代码是一个模块文件export-default.js,它的默认输出是一个函数。

其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。

// import-default.js

import customName from './export-default';

customName(); // 'foo'

上面代码的import命令,可以用任意名称指向export-default.js输出的方法。需要注意的是,这时import命令后面,不使用大括号。