ECMAScript 6 类 应用

来源:互联网 发布:御彩轩时时彩计划软件 编辑:程序博客网 时间:2024/06/05 06:10

近些日子在git上经常看到以es6编写的js代码。

以前有些了解,但没有深入学习。

现在用的人多了,也就找了些时间来学习了下。


应用:

在webpack 中会使用es6。

当然肯定需要模块来翻译成es5的代码:babel


es6文档看了下,我觉得对于类模块这块用处比较大。

在现实中使用也简单方便些。


js 语言传统是通过构造函数,定义并生成新对象。

在es6中引用了class 类。作为对象的模板。通过class关键字,定义类。

新的class写法只是让对象原型的写法更新清晰、更像面向对象编程的语法而以。

和后端写法类似了。

//定义类class Point {  constructor(x, y) {    this.x = x;    this.y = y;  }  toString() {    return '(' + this.x + ', ' + this.y + ')';  }}
constructor j 是构造函数,this 表示实例对象。tostring 是类的方法。

方法的定义  实现是扩展了Point.prototype

实例对象:

var a=new Point(参数)

Point .name  //Point


Class 表达式:

const MyClass = class Me {  getClassName() {    return Me.name;  }};
以上创建了一个类,类名是MyClass而不是Me. me只能在类的内部代码可用。

let inst = new MyClass();inst.getClassName() // Me
当然me是可以省略的

const MyClass = class { /* ... */ };
采用class 表达式,可以写出立即执行的class

let person = new class {  constructor(name) {    this.name = name;  }  sayName() {    console.log(this.name);  }}("张三");person.sayName(); // "张三"
class 不存在变量提升,


class 继承

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

class ColorPoint extends Point {}
上面定义了一个colorpoint 类,继承了point类的所有属性和方法。

但是由于没有部署任何任何,所以这两个类完全一样。等于复制了一个point。

class ColorPoint extends Point {  constructor(x, y, color) {    super(x, y); // 调用父类的constructor(x, y)    this.color = color;  }  toString() {    return this.color + ' ' + super.toString(); // 调用父类的toString()  }}
上面代码定义了新的构造函数,和tostring方法。

方法内的super指向父类的方法。


class 的取值函数get和存值函数set

class MyClass {  constructor() {    // ...  }  get prop() {    return 'getter';  }  set prop(value) {    console.log('setter: '+value);  }}let inst = new MyClass();inst.prop = 123;// setter: 123inst.prop


class的静态方法

class Foo {  static classMethod() {    return 'hello';  }}Foo.classMethod() // 'hello'var foo = new Foo();foo.classMethod()// TypeError: undefined is not a function

staitc可以创建静态方法或属性。


模块的定义和引用。

js一直没有模块体系,无法将一个大程序拆分成互相依赖的小文件。

在es6之前社区制定了一些模块加载方案,最主要的有commonjs 和amd 两种。

前者用于服务器,后者用于浏览器

es6实现了模块功能,完全可以取代commonjs amd规范。


es6模块的设计思想,是尽量的静态化。使得编译时就能确定模块的依赖关系。

以及输入和输出的变量。

// CommonJS模块let { stat, exists, readFile } = require('fs');// 等同于let _fs = require('fs');let stat = _fs.stat, exists = _fs.exists, readfile = _fs.readfile;

上面代码的实质是整体加载fs模块,生成一个对象。然后从这个对象上获取三个方法。这种加载为“运行时加载”

因为只有运行时才能得到这个对象,导致完全没有办法 在编译时做“静态优化”


es6模块不是对象,而是通过export命令显式指定输出的代码,输出时采用静态命令的形式。

// ES6模块import { stat, exists, readFile } from 'fs';
上面是加载fs模块的三个方法,其他方法不加载。

称为“编译加载”,即es6在编译时就完成模块加载。

当然这也导致了没法引用es模块本身,因为它不是对象。


export 命令

模块功能主要由export 和Import 。

export 命令用于规定模块的对外接口。

Import 命令用于输入其他模块提供的功能。

一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。

如果你希望外部能够读取模块内部的某个变量,就必须使用export 输出该变量。

// profile.jsexport var firstName = 'Michael';export var lastName = 'Jackson';export var year = 1958;
对外输出三个变量。

// profile.jsvar firstName = 'Michael';var lastName = 'Jackson';var year = 1958;export {firstName, lastName, year};
也可以这样写。

使用大括号指定要输出的一组变量。

export function multiply (x, y) {  return x * y;};
还可以输出函数或类。


function v1() { ... }function v2() { ... }export {  v1 as streamV1,  v2 as streamV2,  v2 as streamLatestVersion};

export输出的变量就是本来的名字,但是 可以使用as 重合名。

export var foo = 'bar';setTimeout(() => foo = 'baz', 500);
export语句输出的值是动态绑定,绑定其所在的模块。

上在代码输出变量foo 什为bar ,500ms后变成baz


import 命令

js文件可通过import命令加载这个模块。

// main.jsimport {firstName, lastName, year} from './profile';function setName(element) {  element.textContent = firstName + ' ' + lastName;}
import 命令接受一个对象,里面指定要多其他模块导入的变量名。

大括号里的变量名,必须与被导入模块对外接口名称相同。

import { lastName as surname } from './profile';
as 可将输入的的名称,从命名。

import 命令具有提升效果,会提升到整个模块的头部,首先执行。

foo();import { foo } from 'my_module';
上面代码不会报错,因为Import 的执行早于foo的调用。

export { es6 as default } from './someModule';// 等同于import { es6 } from './someModule';export default es6;
模块中可以先输入加载模块,再输出此模块

export 输出和import输入可以结合一起。

import 'lodash'

模块的整体加载

除了指定加载某个输出值,还可以使用整体加载,即用* 指定一个对象,所有输出值都加载在这个对象上面。

export function area(radius) {  return Math.PI * radius * radius;}export function circumference(radius) {  return 2 * Math.PI * radius;}
输出三个方法。

// main.jsimport { area, circumference } from './circle';console.log("圆面积:" + area(4));console.log("圆周长:" + circumference(14));
 上面写法是指定要加载的方法,整体加载如下:

import * as circle from './circle';console.log("圆面积:" + circle.area(4));console.log("圆周长:" + circle.circumference(14));

export default 命令

import命令使用时,用户需要知道所需加载的变量名,否则无法加载。

但为了方便,可以用default 命令,为模块指定默认输出。

// export-default.jsexport default function () {  console.log('foo');}
默认输出一个函数

// import-default.jsimport customName from './export-default';customName(); // 'foo'
加载时import 可以为默认函数指定任意的名称。

需要注意的是,这时Import命令后面,不使用大括号 。

// export-default.jsexport default function foo() {  console.log('foo');}// 或者写成function foo() {  console.log('foo');}export default foo;
default 命令用在非匿名函数前,也是可以的。

// 输出export default function crc32() {  // ...}// 输入import crc32 from 'crc32';// 输出export function crc32() {  // ...};// 输入import {crc32} from 'crc32';
// modules.jsfunction add(x, y) {  return x * y;};export {add as default};// 等同于// export default add;// app.jsimport { default as xxx } from 'modules';// 等同于// import xxx from 'modules';
本质上export default 就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。

// 正确export var a = 1;// 正确var a = 1;export default a;// 错误export default var a = 1;
因为export default 命令其实中是输出一个叫做default的变量,所以它后面不能跟变量声明语句。

import customName, { otherMethod } from './export-default';
可以在一条import语句中,同时输入默认方法和其他变量。


模块的继承

模块间可以继承

// circleplus.jsexport * from 'circle';export var e = 2.71828182846;export default function(x) {  return Math.exp(x);}
以上继承了circle模块。

export * 表示输出circle 模块的所有属性和方法,当然它会忽略default。

export { area as circleArea } from 'circle';
可以将circle 改名后再输出 。



import * as math from "circleplus";import exp from "circleplus";console.log(exp(math.e));
加载模块再定义新引入对象,再获取模块的默认方法定义成exp

import * as math from "circleplus";import exp from "circleplus";console.log(exp(math.e));
import * as math from "circleplus";import exp from "circleplus";console.log(exp(math.e));

es6模块加载的实质

es6模块加载的机制,与commonjs模块完全不同。

commonjs模块输出的是一个值的拷贝,而es模块输出的是值的引用。

拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。

// lib.jsvar counter = 3;function incCounter() {  counter++;}module.exports = {  counter: counter,  incCounter: incCounter,};

// main.jsvar mod = require('./lib');console.log(mod.counter);  // 3mod.incCounter();console.log(mod.counter); // 3
lib加载以后,它的内部变化就不影响输出的counter了。这是因为mod.counter是一个原始类型的值,会被缓存。


es6模块的运行机制,与commonjs不一样。

它遇到模块加载命令Import时,不会执行模块,而是只生成一个动态的只读引用。

等到真的需要用到时,再到模块里去取值。

es6输出有点像地址引用,原始值变了,输入的值也会变。

因此es6模块是动态引用,模块里的变量绑定其白发在的模块。

// lib.jsexport let counter = 3;export function incCounter() {  counter++;}// main.jsimport { counter, incCounter } from './lib';console.log(counter); // 3incCounter();console.log(counter); // 4

// m1.jsexport var foo = 'bar';setTimeout(() => foo = 'baz', 500);// m2.jsimport {foo} from './m1.js';console.log(foo);setTimeout(() => console.log(foo), 500);

// lib.jsexport let obj = {};// main.jsimport { obj } from './lib';obj.prop = 123; // OKobj = {}; // TypeError
由于es6输入的模块变量,只是一个“符号连接”,所以这个变量是只读的。对它进行重新赋值会报错。



0 0
原创粉丝点击