map(function(element,index,arr), thisValue)
传入一个函数,该函数会遍历数组,对每一个元素做变换之后,返回一个新数组
- element: 对应数组的每个元素
- index: 数组元素的下标
- arr: 原数组
- 可选。用作 “this” 的值。如果省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。
let arr = [2, 3, 4]
let arr1 = arr.map(function (element, index, arr) {
return arr[index] + 1
})
let arr2 = arr.map(function (element, index, arr) {
return element + 1
})
console.log(arr);
console.log(arr1);
console.log(arr2);
我们可以通过调用函数的call、apply、bind来改变this的指向
var obj ={
name:'zhangsan',
age:18
}
function print() {
console.log(this);
console.log(arguments);
}
print.call(obj,1,2,3);
print.apply(obj,[1,2,3]);
let fn = print.bind(obj, 1,2,3);
fn();
再说一说这三者的共同点和不同点
共同点:
- 功能角度:三者都能改变this指向,且第一个传递的参数都是this指向的对象
- 传参角度:三者都采用的后续传参的方式
不同点:
- 传参方面:call的传参是单个传递的,而apply后续传递的参数是数组形式(传单个值会报错),而bind没有规定,传递值和数组都可以
- 执行方面:call和apply函数的执行是直接执行的,而bind函数会返回一个函数,然后我们想要调用的时候才会执行。
主要应用场景:
- call 经常用于继承
- apply 经常跟数组有关系,比如借助于数学对象实现数组最大值最小值
- bind 不调用函数,但是还想改变this指向,比如改变定时器内部的this指向
由于箭头函数没有自己的this指针,通过call()或者apply()方法调用一个函数时,只能传递参数(不能绑定this), 他们的第一个参数会被忽略
1. 函数:
最起初,实现模块化的方式是使用函数进行封装。将实现不同功能的代码封装到不同的函数中。通常一个文件就是一个模块,有自己的作用域,只向外暴露特定的变量和函数。
function a() {
}
function b() {
}
缺点:容易发生命名冲突或者数据的不安全性
2. 立即执行函数:
立即执行函数中的匿名函数中有独立的词法作用域,避免了外界访问此作用域的变量。通过函数作用域解决了命名冲突、污染全局作用域的问题
(function(window) {
let name = 'JavaScript'
function foo() {
console.log(`name:${name}`)
}
window.myModule = { foo }
})(window)
<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
myModule.name = 'java'
myModule.foo()
</script>
缺点:不能直接访问到内部的变量
3. CommonJS 规范:
CommonJS的规范主要用在Node.js中,为模块提供了四个接口:module、exports、require、global, CommonJS用同步的方式加载模块(服务器端),在浏览器端使用的是异步加载模块。
暴露模块:
- module.exports = {}
- exports.xxx = ‘xxx’
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
counter: counter,
incCounter: incCounter
}
引入模块:
主要通过require的方式引入, 但是require是Node的语法,在浏览器中无法识别
var mod = require('./lib');
console.log(mod.counter);
mod.incCounter();
console.log(mod.counter)
其它:
const path = require('path');
const m = require('./m.js');
const lodash = require('lodash')
- 核心模块, 直接跳过路径分析和文件定位;
- 路径模块, 直接得出相对路径就好了;
- 自定义模块,先在当前目录的node_modules里找到这个模块,如果没有,它会往上一级目录查找查找上一级的node_modules, 依次往上,直到根目录下都没有,就抛出错误。
特点:
- CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
- 所有代码都运行在模块作用域,不会污染全局作用域
- 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
- 模块加载的顺序,按照其在代码中出现的顺序
AMD和CMD
上面有CommonJS规范了,为什么还出AMD规范,因为CommmonJS是同步加载代码的,在浏览器中会发生堵塞问题,造成页面的无响应。所以浏览器不太适合使用CommonJS来加载。
CommonJS 规范对浏览器端和服务器端的不同之处
- 服务器端所有的模块都存放在本地硬盘中,可以同步加载完成,等待的时间就是硬盘的读取时间。
- 浏览器,所有的模块都放在服务器端,等待的时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态
AMD:
AMD(Asynchronous Module Definition), 即"异步模块定义"。 它主要采用异步方式加载模块,模块的加载不影响它后边语句的运行。所加载的模块,都会定义在回调函数中,加载完成,再执行回调函数
(1)使用方式
defined 是一个javascript库中的一个方法,使用之前需要安装一个库。
npm i requirejs
使用语法如下:
define(id, dependencies, factory)
- id: 一个字符串,表示模块的名称
- dependencies: 一个数组,是我们当前定义的模块要依赖于哪些模块,数组中的每一项表示的是要依赖模块的相对路径
- factory: 工厂方法,具体模块内容
(2)导出模块
将add.js中的一个函数导出语法如下:
define(function() {
var add = function(a,b) {
return a+b;
}
return {
add: add
}
})
(3) 引入模块
导入上述导出的模块
var requirejs = require("requirejs");
requirejs(['add'], funtion(math) {
console.log(add.add(1,2))
})
CMD:
CMD(Common Module Definition), 主要是seajs的规范
AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同,二者皆为异步加载模块
(1) 使用方式
define(function(require, exports, module) {
var $ = require('jquery');
var Spinning = require('./spinning')
exports.doSomething = ...
module.exports = ...
})
define(function (require, exports, module) {
console.log('我比m1 要早加载。。。')
var m1 = require('m1');
var add = function (a, b) {
return a+b;
}
var print = function() {
console.log(m1.name)
}
module.exports = {
add: add,
print: print
}
})
AMD和CMD的区别
- AMD依赖前置, js很方便的就知道要加载的是哪个模块了,因为已经在define的dependencies参数中就定义好了,会立即加载它
- CMD是就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块。只有在用到某个模块的时候再去require
ES6 Moudle
ES6实现的模块就非常简单,用于浏览器和服务器端。import命令会被Javascript引擎静态分析,在编译时就引入模块代码。
(1) export导出模块
const a = 1;
export { a };
export const a = 1;
const a = 1;
export {a as A}
const a = 1;
export default a;
export {a as default}
(2) import 导入模块
import { a } from './module';
import { a as A} from './module';
import './module';
import * as module from './module'
import module, { a } from './module'
ES6和CommonJS的区别
- CommonJS 模块输出的是一个值的拷贝,ES6模块输出的是值的引用
- 所谓值的拷贝,原始类型的值被缓存,不随模块内部的改变而改变。
- ES6模块是动态引用,不缓存值, 模块内外是绑定的,而且是只读引用,不能修改值。ES6的js引擎对脚本静态分析的时候,遇到加载命令模块import, 就会生成一个只读引用, 当真正用到模块里面的值的时候,就会去模块内部去取。
- CommonJS 模块是运行时加载, ES6模块是编译时加载输出接口
- 运行时加载:CommonJS模块就是对象;是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为运行时加载
- 编译时加载:ES6模块不是对象,而是通过export命令显式指定输出的代码。import时采用静态命令的形式,即在import指定加载某个输出值,而不是加载整个模块,这种加载称为编译时加载。
- CommonJS导入的模块路径可以是一个表达式,因为它使用的是require() 方法;而ES6 Modules只能是字符串
- CommonJS this 指向当前模块, ES6 Modules this 指向undefined