函数作用域修改大法

  • Function.prototype.bind()

    bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind() 方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

    语法

    1
    2
    3
    4
    5
    6
    7
    /**
    * thisArg
    * 当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用new 操作符调用绑定函数时,该参数无效。
    * arg1, arg2, ...
    * 当绑定函数被调用时,这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数。
    */

    fun.bind(thisArg[, arg1[, arg2[, ...]]])

    支持情况:ie >= 9、chrome、safari。

    举例(摘自MDN):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function LateBloomer() {
    this.petalCount = Math.ceil(Math.random() * 12) + 1;
    }

    // Declare bloom after a delay of 1 second
    LateBloomer.prototype.bloom = function() {
    window.setTimeout(this.declare.bind(this), 1000);
    };

    LateBloomer.prototype.declare = function() {
    console.log('I am a beautiful flower with ' +
    this.petalCount + ' petals!');
    };

    var flower = new LateBloomer();
    flower.bloom(); // 一秒钟后, 调用'declare'方法

    为了兼容低版本浏览器,可以使用如下 polyfill

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    if (!Function.prototype.bind) {
    Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
    // closest thing possible to the ECMAScript 5
    // internal IsCallable function
    throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var aArgs = Array.prototype.slice.call(arguments, 1),
    fToBind = this,
    fNOP = function () {},
    fBound = function () {
    return fToBind.apply(this instanceof fNOP
    ? this
    : oThis || this,
    aArgs.concat(Array.prototype.slice.call(arguments)));
    };

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();

    return fBound;
    };
    }
  • Function.prototype.call 和 Function.prototype.apply

    举例(摘自MDN):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    function Product(name, price) {
    this.name = name;
    this.price = price;

    if (price < 0) {
    throw RangeError('Cannot create product ' +
    this.name + ' with a negative price');
    }
    }

    function Food(name, price) {
    Product.call(this, name, price);
    this.category = 'food';
    }

    function Toy(name, price) {
    Product.call(this, name, price);
    this.category = 'toy';
    }

    var cheese = new Food('feta', 5);
    var fun = new Toy('robot', 40);
  • $.proxy(fn, context[, arg1[, arg2[, …]]])

    这里使用的 jQuery 方法,接受两个参数,第一个为输入的函数,第二个为要绑定到的作用域,之后的参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数。此方法返回一个作用域为 context 的新函数。

    举例(摘自jQuery):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    <!doctype html>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <title>jQuery.proxy demo</title>
    <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
    </head>
    <body>

    <p><button type="button" id="test">Test</button></p>
    <div id="log"></div>

    <script>
    var me = {
    type: "zombie",
    test: function( event ) {
    // Without proxy, `this` would refer to the event target
    // use event.target to reference that element.
    var element = event.target;
    $( element ).css( "background-color", "red" );

    // With proxy, `this` refers to the me object encapsulating
    // this function.
    $( "#log" ).append( "Hello " + this.type + "<br>" );
    $( "#test" ).off( "click", this.test );
    }
    };

    var you = {
    type: "person",
    test: function( event ) {
    $( "#log" ).append( this.type + " " );
    }
    };

    // Execute you.test() in the context of the `you` object
    // no matter where it is called
    // i.e. the `this` keyword will refer to `you`
    var youClick = $.proxy( you.test, you );

    // attach click handlers to #test
    $( "#test" )
    // this === "zombie"; handler unbound after first click
    .on( "click", $.proxy( me.test, me ) )

    // this === "person"
    .on( "click", youClick )

    // this === "zombie"
    .on( "click", $.proxy( you.test, me ) )

    // this === "<button> element"
    .on( "click", you.test );
    </script>


    </body>
    </html>

Javascript Getters and Setters

Getters 和 setters 是用来读取和设置数据非常好的方式。比方说,你需要从一个对象中读取和设置一个值,如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Field(val){
var a = val;

this.getValue = function(){
return a;
};

this.setValue = function(val){
a = val;
};
}
var field = new Field("test");
field.value
// => undefined
field.setValue("test2")
field.getValue()
// => "test2"

我们可以使用到 getters 和 setters 来重写,重写的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Field(val){
this.a = val;
}

Field.prototype = {
get value() {
return this.a;
},
set value(val) {
this.a = val;
}
};
var field = new Field("test");
field.value
// => "test"
field.value = "test2";
// => "test2"

可以看到,读取值和设置值都是如此简明。get、set 关键字后面的方法分别实现了对 this.a 的读取和设置。获取时 .value 即可,不加括号。设置时,使用 =,= 右边是要设置的值。

使用 getters、setters,让代码更加清晰,明确哪些值是可读的,哪些是可写的。

目前,chrome、safari、firfox、ie>=9 之后都是支持的。

学习 koa

背景

最近项目中首次使用 node 作为前端后台,便于同步渲染模板。项目中,少不了需要选择一个框架来充当骨架。对,我们选择的当红炸子鸡『koa』。

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
// 引入 koa
import koa from 'koa';

// 实例化 koa
let app = new koa();

// 请求返回 hello world
app.use(function *(){
this.body = 'Hello World';
});

// 启动服务器,监听端口 3000
app.listen(3000);

注意,我们使用了 es6 的语法,为了让 node 可以顺利运行,需要先引用 babel/register 。

概括起来,分三步走:

  1. 引入并实例化 koa
  2. 往 koa 中插入中间件,如 koa-router、koa-static 中间件
  3. 启动服务

看源码

以下是 koa/lib/Application.js 部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...

var app = Application.prototype;
function Application() {
...
};
Object.setPrototypeOf(Application.prototype, Emitter.prototype);
app.listen = function() {
...
};
app.use = function() {
...
};
app.callback = function() {
...
};
app.createContext = function() {
...
};
app.onerror = function() {
...
}

看到没有,代码毫无花哨可言,这不就是个普通的构造函数嘛!

下面我们逐个展开看代码

先上 Application function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Application() {
// 检查作用域 this,兼容 new koa() 和 koa() 两种调用方式。这行完全可以删掉,强烈建议程序员使用 new koa() 这种形式
if (!(this instanceof Application)) return new Application;
// 添加 env 对象到 this
this.env = process.env.NODE_ENV || 'development';
// 添加 subdomainOffset 到 this
this.subdomainOffset = 2;
// 初始化 middleware
this.middleware = [];
// 将 context 对象添加到 this
this.context = Object.create(context); // context = require('./context')
// 将 request 对象添加到 this
this.request = Object.create(request); // request = require('./request');
// 将 response 对象添加到 this
this.response = Object.create(response); // response = require('./response');
}

1
2
// Application.prototype = Emitter.prototype
Object.setPrototypeOf(Application.prototype, Emitter.prototype); // Emitter = require('events').EventEmitter

再看 app.use

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 添加中间件
*/

app.use = function(fn){
// 检查 fn 是否是 generator 函数,非将出现错误
if (!this.experimental) {
assert(fn && 'GeneratorFunction' == fn.constructor.name, 'app.use() requires a generator function');
}
debug('use %s', fn._name || fn.name || '-');
// 将 fn 中间件保存到 middleware 数组中
this.middleware.push(fn);
return this;
};

再看 app.callback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 返回服务启动的回调方法
*/

app.callback = function() {
// 且将 this.experimental 定义为 false,只看右边分支
// compose = require('koa-compose')
// compose 将 middleware 数组元素,包装成一个 generator 函数
// co.wrap 将 generator 函数包装秤一个 promise 函数
var fn = this.experimental
? compose_es7(this.middleware)
: co.wrap(compose(this.middleware));
var self = this;

if (!this.listeners('error').length) this.on('error', this.onerror);

// 返回函数
return function(req, res){
res.statusCode = 404;
// 创建作用域
var ctx = self.createContext(req, res);
// 监听 response,完成时执行回调 app.onerror 方法,将错误打印出来
onFinished(res, ctx.onerror);
// 执行 fn,promise 状态为 resolve 时响应请求,将结果返回给请求方
fn.call(ctx).then(function () {
respond.call(ctx);
}).catch(ctx.onerror);
}
}

再看 app.listen

1
2
3
4
5
6
7
app.listen = function(){
debug('listen');
// 创建 sever
var server = http.createServer(this.callback());
// 将 server 开始监听工作
return server.listen.apply(server, arguments);
};

再看 app.createContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 对 this.context 进行扩展,生成新的 context,作为中间件的作用域
*/

app.createContext = function(req, res){
var context = Object.create(this.context);
var request = context.request = Object.create(this.request);
var response = context.response = Object.create(this.response);
context.app = request.app = response.app = this;
context.req = request.req = response.req = req;
context.res = request.res = response.res = res;
request.ctx = response.ctx = context;
request.response = response;
response.request = request;
context.onerror = context.onerror.bind(context);
context.originalUrl = request.originalUrl = req.url;
context.cookies = new Cookies(req, res, this.keys);
context.accept = request.accept = accepts(req);
context.state = {};
return context;
};

至此,Application.js 分析完毕。

再移步到 context.js。context.js 中初始化了 context 的所有方法。

再移步到 response.js、request.js,这两个 js 是对 context.response、context.request 方法的实现。

over!!!

学习 co

co 是使用 ES6 generator 的必然会引用到的第三方库,它很好的解决了 yield 表达式返回值的问题,通过自动的不断调用 .next 使得函数向下执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var co = require('co');

function * yieldFunc() {
var i = 0;
var a = yield ++i;
var a2 = yield ++i;
return {
1: a,
2: a2
};
}

co(function*() {
var ret = yield yieldFunc();
return ret;
}).then(function(ret) {
console.log(ret);
});

上面是一个 co 的使用范例。它接受一个 generator 函数作为参数,返回一个 Promise 对象,将 generator 函数的执行结果作为 resolve 的参数,通过调用 then 方法,将结果打印到控制台。

co 的源码很短,不过 200 来行(注释计算在内了),如果我们只按照上面的例子调用 co,co 可以简化为如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module.exports = simpleCo;
function simpleCo(gen) {
var ctx = this;
return new Promise(function(resolve, reject) {
gen = gen.call(ctx);
fulNext();
function fulNext(res) {
try {
var ret = gen.next(res);
if (!ret.done) {
fulNext(ret.value);
} else {
resolve(ret.value);
}
} catch ( e ) {
reject(e);
}
}
});
}

20 行足矣,源码见 github

ECMAScript 2015 (ES6) 概览

Sublime Text 中运行 ES6

  1. 安装最新版的 node

  2. 配置新的 build 系统

    1. 打开 Tools -> Build System -> New Build System…

    2. 编辑如下:{ “cmd”: [“/usr/local/bin/node”, “–use-strict”, “–harmony_destructuring”, “$file”], “selector”: “source.js”}

    3. 保存成 ES6.sublime-build 到默认路径

  3. 测试

    1. 编辑 test.js

      1
      2
      let [foo, bar] = [1, 2];
      console.log(foo, bar);
    2. 运行: Cmd + B

    3. 控制台输出:1 2

ECMAScript 2015 (ES6) 简介

ECMAScript 6 是 JavaScript 语言的新一代标准,它于2000年开始制定,历经15年,终于在2015年6月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

let 和 const

let 声明局部变量,为Javascript 新增了块级作用域,不允许在同一作用域内,重复声明同一个变量

const 声明常量,必须初始化,一旦声明,不许改变

let 和 const 变量声明不提升

变量的解构赋值

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

解构赋值便于我们一次性声明多个变量,方便提取函数返回值、JSON 数据,允许设置默认值。

数组的解构赋值 模式匹配

1
var [a, [b, c]] = [1, [2, 3]];

解构不成功,变量的值就等于 undefined

1
var [a, b] = [1];

不完全解构

1
var [a, [b], c] = [1, [2, 3], 4];

解构赋值指定默认值

1
var [a, b=2] = [1];

对象的解构赋值

变量必须与属性同名

1
var {a, b} = {a: 1, b: 2};

变量名与属性名不一致是,必须写成下面这样

1
2
var {a: renameA, b} = {a: 1, b: 2};
// a 不被赋值,renameA = 1

解构用于嵌套结构。可把数据结构看成树,仅叶子被解析赋值,其他节点均仅为模式(undefined)。

1
2
3
4
5
6
7
8
9
10
var obj = {
p: [
"Hello",
{ y: "World" }
]
};
var { p: [x, { y }] } = obj;
// p 仅是模式,不会被赋值,p error undefined
var { p } = obj;
// p = ["hello, {y: "World"}"]

字符串的解构赋值

字符串被转换成一个类似数组的对象,类似 ‘hello’.split(‘’),按照对象解构赋值的规则进行

1
const [a, b, c, d, e] = 'hello';

字符串作为字符串对象进行解构赋值

1
let {length: len} = 'hello';

数值和布尔值的解构赋值

将数值和布尔值先转换成对象,再按照对象的规则进行

null, undefined 无法转换成对象,不能进行解构赋值

模板字符串

用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

1
2
3
4
5
6
7
8
9
const world = 'world';

`hello world`;

`
hello world
`


`hello ${world}`

模板字符串中嵌入变量,需要将变量名写在${}之中。大括号内部可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。

标签模板

模板字符串紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。常被用来过滤 HTML 字符串,防止恶意内容。另一个应用,就是多语言转换(国际化)。

正则表达式

u 修饰符,含义为 unicode 模式,用来正确处理四个字节的UTF-16编码。

1
2
3
/^\uD83D/u.test('\uD83D\uDC2A'); // false
/^\uD83D/.test('\uD83D\uDC2A'); // true
/^.$/u.test('我'); // true, . 也能匹配中文(两个字符)了

y 修饰符,也叫『粘连』(sticky)修饰符。

y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。

1
2
3
4
var str = 'aaa_aa_a';
var re = /a+/y;
re.exec(str); // ["aaa"]
re.exec(str); // null

目前,y、u 修饰符都还不支持

数值扩展

进制 前缀
二进制 0b
八进制 0o
十六进制 0x

Number(0x15) 转换成十进制,非数字转换为数值

Number.isFinite 判断非无穷

Number.isNaN 判断非数值

Number.parseInt 转整数

Number.parseFloat 转浮点数

Number.isInteger 判断是否是整数

window.isFinite 对参数先调用 Number()

window.isNaN

Math.trunc 返回数值的整数部分

Math.sign 判断数值是正数、负数、还是零,结果: 1、-1、0、-0、NaN

Iterator(遍历器)

提供统一的访问机制遍历数据集合的成员。供 for…of 使用。

map|set|array

.keys():返回一个键名的遍历器

.values():返回一个键值的遍历器

.entries():返回一个键值对的遍历器
1
2
3
4
for(let [index, value] of [1, 2, 3].entries()) {
index; // 0, 1, 2
value; // 1, 2, 3
}

数组扩展

Array.from 将类似数组的对象和可遍历的对象转换成真正的数组

Array.of 将一组值转换为数组

array.copyWithin(target, start, end) 将 start 位到 end 前一位复制到 target 位开始的位置

1
2
[1, 2, 3, 4, 5].copyWithin(0, 2, -1);
// [3, 4, 3, 4, 5]

array.find((item)=>{return true}) 遍历数组,找出第一个符合条件(回调函数返回 true)的值,将该值返回

array.findIndex 同上,返回该值的位置,找不到符合条件的返回 -1

array.fill(value, start, end) 往原数组的 start 位置到 end 前一个位置填充 value

函数扩展

参数默认值。参数值为 undefined 时,赋予默认值。在尾参数上定义默认值,否则该参数是没法省略的。

指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。

可用于指定某一参数不能被省略,或表明这个参数可以省略

1
2
3
4
5
6
7
8
9
function throwMissing() {
throw new Error('missing');
}

function f(a=throwMissing(), b=2, c=3) {
}
f(1); // a=1, b=2, c=3
f(1, undefined, 4); // a=1, b=2, c=4
f.length; // 0

rest 参数。获取函数多余的参数。ES6 严格模式不能使用 arguments。

1
2
function f(head, ...arg) {}
f(1, 2, 3); //head=1, arg=[2, 3]

扩展运算符(…arrayName)。将数组转换为逗号分隔的参数序列。主要用于函数调用。

应用:

  1. 代替apply

  2. 合并数组

  3. 与解构赋值组合生成数组

  4. 得到正确的字符串长度

  5. 将实现了Iterator接口的对象转换成数组

1
2
3
4
5
6
7
8
9
10
11
12
function push(array, ...items) {
array.push(...items); // [1, 2, 3]
array.push.apply(array, items); // bad case
}
push([], 1, 2, 3);

[1, 2, 3, ...[4, 5]]; // [1, 2, 3, 4, 5]

let [a, ...rest] = [1, 2, 3, 4]; //a=1, rest=[2, 3, 4]

let str = '我shi';
[...str].length; // 5

箭头函数 ()=>{} 语法糖

对象扩展

Object.is 同值相等,基本与 === 一致,但是 +0 不等于 -0, NaN 等于 NaN

Object.assign(target, source, source2) 将 source、source2 对象的自身属性复制到 target 对象,不可枚举属性和继承的属性不被拷贝。对于嵌套的对象,此方法执行的是替换,而非添加。应用:

- 为对象添加属性和方法

- 克隆对象

- 合并对象

- 为对象属性指定默认值

Set 和 WeakSet

它类似于数组,但是成员的值都是唯一的,没有重复的值。WeakSet 的成员只能是对象。

1
new Set([1, 2, 2, 3, 4, 4])

set.size set成员个数

set.add 添加成员

set.delete 删除成员

set.has 检查是否拥有某值

set.clear 清空set

Map 和 WeakMap

类似于 Object,但是 Map 的键不局限于字符串。WeakMap 的键只能是对象,NaN 除外。

map.size 成员个数

map.set(key, value) 添加成员

map.get(key) 返回指定 key 的成员的值,找不到则返回 undefined

map.has 检查数据中是否含有某值

map.delete 删除指定键值成员,成功返回 true,失败返回 false

map.clear 清空map

WeakSet 和 WeakMap

没有 size 属性,没有遍历操作,无法清空。

典型应用是,一个对应DOM元素的WeakMap结构,当某个DOM元素被清除,其所对应的WeakMap记录就会自动被移除。基本上,WeakMap的专用场合就是,它的键所对应的对象,可能会在将来消失。WeakMap结构有助于防止内存泄漏。

1
2
3
4
5
6
7
8
9
var wm = new WeakMap();
var element = document.querySelector(".element");

wm.set(element, "Original");
wm.get(element) // "Original"

element.parentNode.removeChild(element);
element = null;
wm.get(element) // undefined

Generator 函数

1
2
3
4
5
6
7
8
9
10
function* f() {
yield '1';
console.log(1);
yield '2';
console.log(2);
}
var it = f();
it.next(); // 执行 yield '1',等到 next 命令再向下执行
it.next(); // 1
it.next(); // 2

形式上,function 与方法名中间有(*)号,函数内部用 yield(产出),定义不同内部状态。yield 只能出现在 generator 函数中。

执行 generator 函数会返回一个遍历器,不断的执行 next,遍历函数的每一个状态。

yield 语句本身没有返回值,通过在 next 带上一个参数,设置上一个 yield 的返回值。

1
2
3
4
5
6
7
8
9
function* f(x=1) {
var y = yield (x + 1);
var z = yield (x + y);
return x + y + z;
}
var it = f();
it.next(); // x=1, y=undefined, z=undefined
it.next(4); // x=1, y=4, z=undefined
it.next(10); // x=1, y=4, z=10

for … of … 可代替 next

如果在 generator 函数中再调用其他 generator 函数,需要使用 yield * 语句

1
function * bar() {
  yield 1;
}
function * foo() {
  yield * bar();
}

Promise

一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的API,可供进一步处理。

1
2
3
4
5
6
7
8
9
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('a');
}, 2000);
});
p.then(function(result) {
console.log(result);
});
// 2秒后输出 a

promise.then 为 promise 实例添加状态改变时的回调函数,第一个参数为 resolved 的回调,第二个参数是 rejected 的回调

promise.catch 指定发生错误时的回调函数

Promise.race 将多个 promise 实例包装成一个新实例,只要一个实例的状态改变了,新实例的状态就跟着改变了,传递给回调函数的值为率性改变状态示例的返回值

Promise.all 将多个 Promise 实例包装秤一个新实例,所有的实例状态改变了,新实例的状态才会改变,新实例的状态由各个实例的最终状态执行『且』运算得到,传递给回调函数的值为每个实例结果组成的数组

Promise.resolve 返回一个状态为 resolved 的实例

Promise.reject 返回一个状态为 rejected 的实例

Class

ECMAScript 5 构造函数的语法糖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A {
constructor() {
this.a = 'a';
}
sayIt() {
alert(this.a);
}
}
// ES 5
function A() {
this.a = 'a';
}
A.prototype.sayIt = function() {
alert(this.a);
};

Class 继承

1
2
3
4
5
6
7
8
9
10
11
class B extends A {
constructor() {
super();
this.a = 'b';
}
sayIt() {
super.sayIt();
}
}
var b = new B();
b.sayIt();

super关键字指向父类

static 关键字,表示该方法不会被实例继承,而是直接通过类来调用,被称为静态方法。静态方法会被继承。

1
2
3
4
5
6
7
class A() {
constructor() {}
static sayHi() {
console.log('hi');
}
}
A.sayHi();

静态属性。class 内部只有静态方法,没有静态属性。

1
2
class A() {}
A.hi = 'hi';

模块

通过export命令显式指定输出的代码,输入时采用import静态命令

export 命令

1
2
3
4
// jackson.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
1
2
3
4
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};

as 重命名对外接口名称

1
2
3
4
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName as fn, lastName as ln, year as y};

export default 为模块指定默认输出

1
2
// jackson2.js
export default {firstName: 'Mickael', lastName: 'Jackson', year: 1958};

import 命令

引入具体的值

1
import {firstName, lastName, year} from './jackson';

全部引入

1
import * as jackson from './jackson';

引入使用 export default 的模块

1
import jackson from './jackson2';