持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
一,什么是组件化
按照官方的理解,是能够单独命名并独立地完成一定功能的程序语句的集合(即程序代码和数据结构的集合体),但是,按照我们自己的理解来说,就是把项目中一些重复(多次使用)的功能模块单独封装成一个集合(可以是一整个文件,也可以是一个函数,等等等等)
二,为什么组件化如此盛行
如果没有模块化,我们代码会怎样?
- 变量和方法不容易维护,容易污染全局作用域
- 加载资源的方式通过script标签从上到下。
- 依赖的环境主观逻辑偏重,代码较多就会比较复杂。
- 大型项目资源难以维护,特别是多人合作的情况下,资源的引入会让人奔溃
因此,需要一种将JavaScript程序模块化的机制,如
- CommonJs (典型代表:node.js早期)
- AMD (典型代表:require.js)
- CMD (典型代表:sea.js)
AMD
Asynchronous ModuleDefinition(AMD),异步模块定义,采用异步方式加载模块。所有依赖模块的语句,都定义在一个回调函数中,等到模块加载完成之后,这个回调函数才会运行代表库为`require.js````
/** main.js 入口文件/主模块 **/ // 首先用config()指定各模块路径和引用名 require.config({ baseUrl: "js/lib", paths: { "jquery": "jquery.min", //实际路径为js/lib/jquery.min.js "underscore": "underscore.min", } }); // 执行基本操作 require(["jquery","underscore"],function($,_){ // some code here });
### CommonJs
### `CommonJS` 是一套 `Javascript` 模块规范,用于服务端```
// a.js module.exports={ foo , bar} // b.js const { foo,bar } = require('./a.js')
```其有如下特点:- 所有代码都运行在模块作用域,不会污染全局作用域
- 模块是同步加载的,即只有加载完成,才能执行后面的操作
- 模块在首次执行后就会缓存,再次加载只返回缓存结果,如果想要再次执行,可清除缓存
- `require`返回的值是被输出的值的拷贝,模块内部的变化也不会影响这个值既然存在了`AMD`以及`CommonJs`机制,`ES6`的`Module`又有什么不一样?ES6 在语言标准的层面上,实现了`Module`,即模块功能,完全可以取代 `CommonJS`和 `AMD`规范,成为浏览器和服务器通用的模块解决方案`CommonJS` 和`AMD` 模块,都只能在运行时确定这些东西。比如,`CommonJS`模块就是对象,输入时必须查找对象属性```
// CommonJS模块 let { stat, exists, readfile } = require('fs'); // 等同于 let _fs = require('fs'); let stat = _fs.stat; let exists = _fs.exists; let readfile = _fs.readfile;
````ES6`设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量```
// ES6模块 import { stat, exists, readFile } from 'fs';
```上述代码,只加载3个方法,其他方法不加载,即 `ES6` 可以在编译时就完成模块加载由于编译加载,使得静态分析成为可能。包括现在流行的`typeScript`也是依靠静态分析实现功能
## 三,使用场景
基于`Decorator`强大的作用,我们能够完成各种场景的需求,下面简单列举几种:
使用`react-redux`的时候,如果写成下面这种形式,既不雅观也很麻烦
class MyReactComponent extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
通过装饰器就变得简洁多了
@connect(mapStateToProps, mapDispatchToProps) export default class MyReactComponent extends React.Component {}
将`mixins`,也可以写成装饰器,让使用更为简洁了
function mixins(...list) { return function (target) { Object.assign(target.prototype, ...list); }; }
// 使用 const Foo = { foo() { console.log('foo') } };
@mixins(Foo) class MyClass {}
let obj = new MyClass(); obj.foo() // "foo"
下面再讲讲`core-decorators.js`几个常见的装饰器
#### @antobind
`autobind`装饰器使得方法中的`this`对象,绑定原始对象
import { autobind } from 'core-decorators';
class Person { @autobind getPerson() { return this; } }
let person = new Person(); let getPerson = person.getPerson;
getPerson() === person; // true
#### @readonly
`readonly`装饰器使得属性或方法不可写
import { readonly } from 'core-decorators';
class Meal { @readonly entree = 'steak'; }
var dinner = new Meal(); dinner.entree = 'salmon'; // Cannot assign to read only property 'entree' of [object Object]
#### @deprecate
`deprecate`或`deprecated`装饰器在控制台显示一条警告,表示该方法将废除
import { deprecate } from 'core-decorators';
class Person { @deprecate facepalm() {}
@deprecate('功能废除了') facepalmHard() {} }
let person = new Person();
person.facepalm(); // DEPRECATION Person#facepalm: This function will be removed in future versions.
person.facepalmHard(); // DEPRECATION Person#facepalmHard: 功能废除了