JS模块:ES6 AMD CMD commonJS

前端之家收集整理的这篇文章主要介绍了JS模块:ES6 AMD CMD commonJS前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

总结

ES6 import 循环依赖 惰性加载
amd 异步 依赖管理 (require.js)
cmd 异步 依赖就近 (sea.js)
commonjs 同步

PS:

cmd (还要解析一下字符串,比amd多一道工序)

define(function(require,exports,module) {
   var clock = require('clock');
   clock.start();
});

amd

require(['clock'],function(clock){
  clock.start();
});

ES6模块不会缓存运行结果,而是动态地去被加载的模块取值,以及变量总是绑定其所在的模块。

ES6通过惰性加载解决了循环引用问题

ES6模块的运行机制与CommonJS(以及requireJS= CommonJS的加载方式)不一样,它遇到模块加载命令import时,不会去执行模块,而是只生成一个引用。等到真的需要用到时,再到模块里面去取值。
因此,ES6模块是动态引用,不存在缓存值的问题,而且模块里面的变量,绑定其所在的模块。请看下面的例子。

ES6根本不会关心是否发生了"循环加载",只是生成一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值。

ES6不取值,而是给引用

// a.js
import {bar} from './b.js';
export function foo() {
  bar();  
  console.log('执行完毕');
}
foo();

// b.js
import {foo} from './a.js';
export function bar() {
if (Math.random() > 0.5) {
foo();
}
}

按照CommonJS规范,上面的代码是没法执行的。a先加载b,然后b又加载a,这时a还没有任何执行结果,所以输出结果为null,即对于b.js来说,变量foo的值等于null,后面的foo()就会报错。

但是,ES6可以执行上面的代码

  • 默认参数
ES5

function point(x,y,isFlag){
x = x || 0;
y = y || -1;
isFlag = isFlag || true;
console.log(x,isFlag);
}
point(0,0) // 0 -1 true
point(0,false) // 0 -1 true
point(1) // 1 -1 true
point() // 0 -1 true

以上,如果默认参数是布尔值或将值设为 0,是没有用的。必须改为:

ES5

function point(x,isFlag){
x = x || 0;
y = typeof(y) === 'undefined' ? -1 : y;
isFlag = typeof(isFlag) === 'undefined' ? true : isFlag;
console.log(x,0) // 0 0 true
point(0,false) // 0 0 false
point(1) // 1 -1 true
point() // 0 -1 true

ES6

//有了 ES6,现在可以用更少的代码实现更好的效果了。
ES6

function point(x = 0,y = -1,isFlag = true){
console.log(x,false) // 0 0 false
point(1) // 1 -1 true

var link = function(height = 50,color = 'red',url = 'http://azat.co') {
  ...
}
  • 模板对象
var name = `Your name is ${first} ${last}. `;
var url = `http://localhost:3000/api/messages/${id}`;
  • 解构赋值
var { house,mouse} = $('body').data(); // we'll get house and mouse variables
var {jsonMiddleware} = require('body-parser');
var {username,password} = req.body;
  • 箭头函数
var logUpperCase = function() {
  this.string = this.string.toUpperCase();
  return () => console.log(this.string);
}
logUpperCase.call({ string: 'ES6 rocks' })();

原因:箭头函数没有独立执行上下文( this ),所以其内部引用 this 对象会直接访问父级。

  • promise
var wait1000 =  ()=> new Promise((resolve,reject)=> {setTimeout(resolve,1000)});
wait1000()
    .then(function() {
        console.log('Yay!')
        return wait1000()
    })
    .then(function() {
        console.log('Wheeyee!')
    });
console.log('bibiniao')
//bibiniao
//Yay!
//Wheeyee!
  • 块作用域和构造let和const
function calculateTotalAmount (vip) {
  var amount = 0; // probably should also be let,but you can mix var and let
  if (vip) {
    let amount = 1; // first amount is still 0
  } 
  { // more crazy blocks!
    let amount = 100; // first amount is still 0
    {
      let amount = 1000; // first amount is still 0
    }
  }  
  return amount;
}

console.log(calculateTotalAmount(true)); // 0

  • const let
//谈到const,就更加容易了;它就是一个不变量,也是块级作用域就像let一样。下面是一个演示,这里有一堆常量,它们互不影响,因为它们属于不同的块级作用域:
function calculateTotalAmount (vip) {
  const amount = 0;  
  if (vip) {
    const amount = 1;
  } 
  { // more crazy blocks!
    const amount = 100 ;
    {
      const amount = 1000;
    }
  }  
  return amount;
}
console.log(calculateTotalAmount(true));
//从我个人看来,let 和const使这个语言变复杂了。没有它们的话,我们只需考虑一种方式,现在有许多种场景需要考虑。

就 let 而言,他的使用场景应该是相对较少的,我们只会在 loop(for,while 循环)及少量必须重定义的变量上用到他。

猜想:就执行效率而言,const 由于不可以重新赋值的特性,所以可以做更多语法静态分析方面的优化,从而有更高的执行效率。

所以上面代码中,所有使用 let 的部分,其实都应该是用 const 的。

  • 解构
const bookSet = ['UED','TB fed','Not find'];
const bookCollection = () => {
  return {book1: 'UED',book2: 'TB fed'};
};

// 1. 解构也可以设置默认值
const {book1,book3 = 'Not find'} = bookCollection();

// 2. 解构数组时候是可以跳过其中某几项的
const [book1,book3] = bookSet; // book1 = 'UED',book3 = 'Not find'

// 3. 解构可以取到指定对象的任何属性,包括它包含的方法
const {length: setLength} = bookSet; // setLength = 3

  • 增强的对象字面量
const _bookNum = 4;

const basicConfig = {
level: 5
}

const config = {
// 直接指定原型对象
proto: basicConfig,// 属性简写
_bookNum,// 方法简写
getBookNum() {
return this.bookNum;
}
}

  • Classes (类)
class baseModel {
  constructor(options,data) { // class constructor,node.js 5.6暂时不支持options = {},data = []这样传参
    this.name = 'Base';
    this.url = 'http://azat.co/api';
    this.data = data;
    this.options = options;
   }
getName() { // class method
    console.log(`Class name: ${this.name}`);
}

}

  • Modules (模块)

它们是用于描述JavaScript库与类之间交互的接口标准.

AMD依赖前置,js可以方便知道依赖模块是谁,立即加载;

而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略。

commonJS实例: node模块加载方式

这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态。

首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。

普通方式,文件请求会同步发送,但浏览器会等待文件回来,然后一个个执行,此时浏览器假死。

(1)实现js文件的异步加载,避免网页失去响应;
(2)管理模块之间的依赖性,便于代码的编写和维护。

  • 加载非规范的模块
    理论上,require.js加载的模块,必须是按照AMD规范、用define()函数定义的模块。但是实际上,虽然已经有一部分流行的函数库(比如jQuery)符合AMD规范,更多的库并不符合。那么,require.js是否能够加载非规范的模块呢?

回答是可以的。
这样的模块在用require()加载之前,要先用require.config()方法,定义它们的一些特征。
举例来说,underscore和backbone这两个库,都没有采用AMD规范编写。如果要加载它们的话,必须先定义它们的特征。

  require.config({
    shim: {

      'underscore':{
        exports: '_'
      },      'backbone': {
        deps: ['underscore','jquery'],        exports: 'Backbone'
      }
    }
  });

\7. 下列符合规范的AMD模块ID有?(A)

A ./foo/boo/woo    B foo/boo/Woo    C foo/boo/woo.js    D ../../foo/Boo/WoO

参考:AMD规范

symbol

应用:

var obj = {
    a: 1
};
var safeKey = Symbol("know");
console.log(safeKey);//Symbol(know)
obj[safeKey] = 'value';
console.log(obj[safeKey]);  // value

obj["know"]
undefined
obj
{ a: 1 }
obj[safeKey]
'value'
var bKey = Symbol('know')
undefined
bKey === safeKey
false
bKey == safeKey
false

...rest替代arguments

function foo(a,b,...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}

foo(1,2,3,4,5);
// 结果:
// a = 1
// b = 2
// Array [ 3,5 ]

猜你在找的程序笔记相关文章