JS 模块化、组件化、工程化相关的 15 道面试题
  • 1.什么是模块化?
  • 2.简述模块化的发展历程?
  • 3.AMD、CMD、CommonJS 与 ES6 模块化的区别?
  • 4.它们是如何使用的?
  • 5.export 是什么?
  • 6.module.export、export 与 export defalut 有什么区别?
  • 7.什么是组件化?
  • 8.组件化的原则是什么?
  • 9.全局组件与局部组件的区别?
  • 10.如何注册一个全局组件,并使用它?
  • 11.局部组件又是如何注册并使用的?
  • 12.如何封装一个高复用的 Vue 前端组件?
  • 13.什么是前端工程化思想?
  • 14.工程化可以解决什么问题?
  • 15.是如何处理这些问题的?

问:1.什么是模块化?

答:

将 JS 分割成不同职责的 JS,解耦功能,来用于解决全局变量污染、 变量冲突、代码冗余、依赖关系难以维护等问题的一种 JS 管理思想,这就是模块化的过程。


问:2.简述模块化的发展历程?

答:

模块化的发展主要从最初的无模块化,发展到闭包式的 IIFE 立即执行解决模块化,到后来的 CommonJS、 AMD、CMD,直到 ES6 模块化规范的出现。

// jQuery风格的匿名自执行
(function(window) {
//代码
window.jQuery = window.$ = jQuery; //通过给window添加属性而暴漏到全局
})(window);

问:3.AMD、CMD、CommonJS 与 ES6 模块化的区别?

答:

CommonJS 是 NodeJs 的一种模块同步加载规范,一个文件即是一个模块,使用时直接 require(),即可,但是不适用于客户端,因为加载模块的时候有可能出现‘假死’状况,必须等模块请求成功,加载完毕才可以执行调用的模块。但是在服务期不存在这种状况。

AMD (Asynchronous Module Definition):异步模块加载机制。requireJS 就是 AMD 规范,使用时,先定义所有依赖,然后在加载完成后的回调函数中执行,属于依赖前置,使用:define()来定义模块,require([module], callback)来使用模块。

AMD 同时也保留 CommonJS 中的 require、exprots、module,可以不把依赖罗列在 dependencies 数组中,而是在代码中用 require 来引入。

// AMD规范
require(['modA'], function(modA) {
modA.start();
}); // AMD使用require加载模块
define(function() {
console.log('main2.js执行');
require(['a'], function(a) {
a.hello();
}); $('#b').click(function() {
require(['b'], function(b) {
b.hello();
});
});
});

缺点:属于依赖前置,需要加载所有的依赖, 不可以像 CommonJS 在用的时候再 require,异步加载后再执行。

CMD(Common Module Definition):定义模块时无需罗列依赖数组,在 factory 函数中需传入形参 require,exports,module,然后它会调用 factory 函数的 toString 方法,对函数的内容进行正则匹配,通过匹配到的 require 语句来分析依赖,这样就真正实现了 CommonJS 风格的代码。是 seajs 推崇的规范,是依赖就近原则。

// CMD规范
// a.js
define(function(require, exports, module) {
console.log('a.js执行');
return {
hello: function() {
console.log('hello, a.js');
}
};
}); // b.js
define(function(require, exports, module) {
console.log('b.js执行');
return {
hello: function() {
console.log('hello, b.js');
}
};
}); // main.js
define(function(require, exports, module) {
var modA = require('a');
modA.start(); var modA = require('b');
modB.start();
});

ES6 模块化是通过 export 命令显式的指定输出的代码,输入也是用静态命令的形式。属于编译时加载。比 CommonJS 效率高,可以按需加载指定的方法。适合服务端与浏览器端。

// a.js
export var a = 'a';
export var b = function() {
console.log(b);
};
export var c = 'c'; // main.js
import { a, b } from 'a.js'; console.log(a);
console.log(b);

区别:

AMD 和 CMD 同样都是异步加载模块,两者加载的机制不同,前者为依赖前置、后者为依赖就近。

CommonJS 为同步加载模块,NodeJS 内部的模块管理规范,不适合浏览器端。

ES6 模块化编译时加载,通过 export,import 静态输出输入代码,效率高,同时适用于服务端与浏览器端。


问:4.它们是如何使用的?

答:

CommonJS 使用 module.exports,向外暴露模块,使用 require()引入模块,然后直接调用其中的数据或方法。

// m1.js 模块定义
module.exports={
'date1':123,
'date2':{a:1,b:'hello'},
'function1':function(){...},
};
// main.js 模块使用
var module=require(m1.js);
module.data1;
module.data2;
module.function1();

AMD 使用 define(['m1','m2','m3',...],function(m1,m2,m3,...){})来定义模块内部的输出,使用 require(['m1','m2',...],function(m1,m2,...){})来调用模块并使用它。

// 定义:
define(['module1','module2','module3',...],function(module1,module2,module3,...){}) // 引入并调用:
require(['modA'], function(modA) {
modA.start();
});

CMD 用 define(factory)来定义模块或使用它,factory 可以是数据也可以是方法,而后 define 内部通过 module.exports 向外部暴露 。在使用时,,通过工厂函数 function(require, exports, module)中的 require 来引入其他模块并使用该模块。

// 定义 m1.js
define(function (require, exports, module) {
//内部变量数据
var data = 'atguigu.com'
//内部函数
function show() {
console.log('module1 show() ' + data)
}
//向外暴露
exports.show = show
});
// m2.js
define(function(require, exports, module) {
module.exports = {
msg: 'I Will Back'
};
});
// m3.js
define(function (require, exports, module) {
const API_KEY = 'abc123'
exports.API_KEY = API_KEY
});
// m4.js
define(function (require, exports, module) {
//引入依赖模块(同步)
var module2 = require('./module2')
function show() {
console.log('module4 show() ' + module2.msg)
}
exports.show = show
//引入依赖模块(异步),最后执行,因为是异步的,主线的先执行完才会执行这
require.async('./module3', function (m3) {
console.log('异步引入依赖模块3 ' + m3.API_KEY)
})
}); // main.js调用模块并使用
define(function (require) {
var m1 = require('./m1')
var m4 = require('./m3')
m1.show()
m4.show()
});

5.export 是什么?

答:

export 是 ES6 中用于向外暴露数据或方法的一个命令。

通常使用 export 关键字来输出一个变量,该变量可以是数据也可以是方法。

而后,使用 import 来引入,并使用它。

// a.js
export var a = 'hello';
export function sayHello(name) {
console.log('Hello,' + name);
} // main.js
import { a, sayHello } from './a.js';
console.log(a);
console.log(sayHello('LiMing'));

问:6.export defalut、export 与 module.exports 有什么区别?

答:

都是用于向外部暴露数据的命令。

export defalut 与 export 是 ES6 Module 中对外暴露数据的。

export defalut 是向外部默认暴露数据,使用时 import 引入时需要为该模块指定一个任意名称,import 后不可以使用{};

export 是单个暴露数据或方法,利用 import{}来引入,并且{}内名称与 export 一一对应,{}也可以使用 as 为某个数据或方法指定新的名称;

module.exports 是 CommonJS 的一个 exports 变量,提供对外的接口。

// export defalut示例
// a.js
var a='Hello World!';
export defalut=a;
// main.js
import A from 'a.js';
console.log(A); // export 示例
// b.js
export var b='b';
export function sayHello(name){
console.log(name+'Hello World!');
}
// main.js
import {b,sayHello} from 'b.js'
sayHello('LiMing');
console.log(b); // module.exports示例
// c.js
var c='123';
function getValue(){
return c;
}
function updateValue(value){
c=value;
}
module.exports={
getValue,
updateValue
}
// main.js
import handleEvent from 'c.js';
handleEvent.getValue();
handleEvent.updateValue('456');

问:7.什么是组件化?

答:

组件化主要是从 Html 角度把页面解耦成一个一个组件的过程,便于代码的高复用、单一职责、方便维护、避免代码冗余的一种解决方案。


问:8.组件化的原则是什么?

答:

组件的主要原则就是单一职责,高复用性。在前端的开发中,我们通常会对一个页面解耦拆分成许多组件,确保一个组件只负责一个事情,同时尽可能减少外部的关联,组件的相关逻辑只在组件内部处理,利用传递参数,事件通信来保持组件对外的通信。

对于 Vue 项目来说,我们一般把页面中频繁使用的组件,注册为全局可用;其他的按需在页面中局部使用。

问:9.全局组件与局部组件的区别?

答:

全局组件经过注册后,全局可用,可以在任何地方使用,局部组件我们一般定义好后,在页面需要的地方按需引入。

在 Vue 中,全局组件一般是全局使用的 Toast、Loading、Confirm 等,而局部组件是页面中的某个功能的 vue 组件;

另外全局组件与局部组件注册方式不同。


问:10.Vue 如何注册一个全局组件,并使用它?

答:

一般我们定义好.vue 的组件后,通过 import 引入,使用 Vue.Component()来注册全局注册组件。这样我们就可以在其他地方使用它了。


问:11.Vue 局部组件又是如何注册并使用的?

答:

局部组件也是通过 import 引入,不同的是在 Vue 实例中 components 对象中注册,我们就可以在 templete 中使用了。


问:12.如何封装一个高复用的 Vue 前端组件?

答: 1.我们可以把页面上的每个独立的可视/可交互区域/相同页面功能视为一个组件来解耦页面; 2.当我们确定了一个 vue 组件后,再从 html、css 和 js 三个方面把组件的自身逻辑放入组件内部,然后通过 Props,$emit 来保持与父组件进行传输的传递与事件的通信,对于跨父子关系的组件间,使用 eventBus 来做通信; 3.最后我们就可以在使用的地方使用 import 引入,Vue.Component(),或实例的 components 来注册它,最后在页面模板中使用; 4.组件内部我们可能用到动态 class、动态 style、组件的 Props 双向绑定、组件的生命周期等,具体逻辑需要根据组件本身功能来动态调优。


问:13.什么是前端工程化思想?

答:

前端工程化是把前端项目当成一个工程,制定合理的开发流程、工具集的使用以及合理的开发规范,来贯穿开发、优化、测试、代码管理,到发布部署的一种管理思想。


问:14.工程化可以解决什么问题?

答:

前端工程化可以解决业务代码维护难,开发流程不统一,代码格式风格多样性,测试覆盖率低成效不显著, 发布部署流程繁琐复杂等问题。


问:15.是如何处理这些问题的?

答:

对于一个好的前端工程我们一般都是从以下方面来着手:

制定开发规范:包含高效率的开发流程、代码命名/注释/文档规范,合理的目录结构,数据请求规范,路由管理方案,静态资源处理等等;

模块化规范:统筹模块化方案,合理设计全局模块以及按需引入的局部模块的使用,使用可靠的三方工具库,尽可能减少代码冗余,保证模块的单一职责,高聚低耦等;

组件化开发:尽可能拆分为组件,封装各个组件的功能,保证组件的高复用性、灵活性以及与外部的通信畅通;

性能优化:对工程作必要的性能测试,对于性能瓶颈项制定解决方案,并做持续优化。优化数据请求,合并请求,Node 中间件优化请求数据,对静态资源压缩/CDN 部署,尽可能使用字体图标代替图片资源,合理的使用数据缓存等等;

项目测试:编写必要的单元测试,保证功能的可靠性,处理好逻辑的边界问题以及合理的容错机制;

发布部署:使用持续集成,持续交付的管理模式来简化发布部署流程,提高发布部署的效率,将更多的时间转移至功能开发测试上;

开发流程:优化开发流程,保证需求评审、技术评估、业务开发、测试、debugger 以及发布上线的高效率沟通,输出留存必要的协作文档资料,尽可能地减少无效沟通,采用小组式敏捷开发思想;

开发工具集:使用必要的工具集,提升开发管理效率,比如使用编辑器 VSCode 与其插件、代码管理工具与平台 Svn/Git/SourceTree/Gitee/GitLab、Webapack 打包工具 + npm script 开发工作流、Tapd 协作平台、产品设计平台 Axure/ 蓝湖、思维导图 XMind 等等。


面试指南」JS 模块化、组件化、工程化相关的 15 道面试题的更多相关文章

  1. 「面试指南」JS数组Array常用算法,Array算法的一般解答思路

    先看一道面试题 在 LeetCode 中有这么一道简单的数组算法题: // 给定一个整数数组 nums 和一个目标值 target, // 请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下 ...

  2. vue.js原生组件化开发(一)——组件开发基础

    前言 vue作为一个轻量级前端框架,其核心就是组件化开发.我们一般常用的是用脚手架vue-cli来进行开发和管理,一个个组件即为一个个vue页面,这种叫单文件组件.我们在引用组件之时只需将组件页面引入 ...

  3. Android项目模块化/组件化开发(非原创)

    文章大纲 一.项目模块化初步介绍二.项目模块化的两种模式与比较三.大型项目模块化的演进四.项目模块化总结五.参考文章   一.项目模块化初步介绍 1. 前言 在Android开发中,随着项目的不断扩展 ...

  4. vue.js原生组件化开发(二)——父子组件

    前言 在了解父子组件之前应先掌握组件开发基础.在实际开发过程中,组件之间可以嵌套,也因此生成父子组件. 父子组件创建流程 1.构建父子组件 1.1 全局注册 (1)构建注册子组件 //构建子组件chi ...

  5. 「面试指南」解读JavaScript原始数据类型

    JavaScript 有 7 种原始数据类型: String(字符型) Number(数值型) Boolean(布尔值型) Undefined Null Object(对象型) Symbol(符号型, ...

  6. 移动web端的react.js组件化方案

     背景: 随着互联网世界的兴起,web前端开发的方式越来越多,出现了很多种场景开发的前端架构体系,也对前端的要求日益增高,早已经不是靠一个JQuery.js来做前端页面的时代了,而今移动端变化最大,近 ...

  7. Android 开发:由模块化到组件化(一)

    在Android SDK一文中,我们谈到模块化和组件化,现在我们来聊聊组件化开发背后的哪些事.最早是在广告SDK中应用组件化,但是同样适用于普通应用开发 以下高能,请做好心理准备,看不懂请发私信来交流 ...

  8. [Android Pro] 由模块化到组件化(一)

    cp from : https://blog.csdn.net/dd864140130/article/details/53645290 在Android SDK一文中,我们谈到模块化和组件化,现在我 ...

  9. Android 开发:由模块化到组件化

    在Android SDK一文中,我们谈到模块化和组件化,现在我们来聊聊组件化开发背后的哪些事.最早是在广告SDK中应用组件化,但是同样适用于普通应用开发 以下高能,请做好心理准备,看不懂请发私信来交流 ...

随机推荐

  1. C++走向远洋——49(项目一2、复数类中的运算符重载、类的友元函数)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  2. js操作复选框

    js操作复选框 JavaScript 代码: //复选框全选 $(function () { $("#select_all").click(function () { $(&quo ...

  3. Java入门教程八(面向对象)

    对象概念 一切皆是对象.把现实世界中的对象抽象地体现在编程世界中,一个对象代表了某个具体的操作.一个个对象最终组成了完整的程序设计,这些对象可以是独立存在的,也可以是从别的对象继承过来的.对象之间通过 ...

  4. 第六周学习笔记,vc各类控件的输入输出

    6w学习笔记 vc控件的输入输出 单选按钮 当单击 RadioButton 控件时,其 Checked 属性设置为 true,并且调用 Click 事件处理程序.当 Checked 属性的值更改时,将 ...

  5. 配置ubunto 流量使用限制 python 实现简单 http server

    很多ubunto 都有流量限制,使用流量.如每天使用200M ,超过了就要提示信息 原理,在本机 开一个 http 服务, 显示错误信息,哪流量使用完以后,使用 iptables 将 流量转发到 本机 ...

  6. 项目团队测试改进&产品测试方法的思考和改进

    七月份了,2019年已过去一半: 后半年,我们要以什么样的成果来对生命唱赞歌? 我目前负责公司一个小产品线的测试,和一个大产品线的项目测试. 产品测试,我才加入3周: 经过这段时间断断续续的磨合,我对 ...

  7. Yaml文件,超详细讲解

    YAML文件简单介绍 YAML 是一种可读性非常高,与程序语言数据结构非常接近.同时具备丰富的表达能力和可扩展性,并且易于使用的数据标记语言. YAML全称其实是"YAML Ain't a ...

  8. 部署nginx后无法访问数据库,查看www-error.log日志报错Class 'mysqli' not found in /usr/local/nginx/html/mysql.php on line 2

    检查你的php-mysql包是否安装 [root@localhost nginx]# rpm -qa php-mysql 没有任何输出则没有安装,接下来用yum安装php-mysql yum -y i ...

  9. 为什么vue中的data用return返回呢?

    不使用return包裹的数据会在项目的全局可见,会造成变量污染:使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件. 当一个组件被定义, data 必须声明为返回一个初始数据对象的函 ...

  10. LeetCode-矩形重叠

    题目描述: 矩形以列表 [x1, y1, x2, y2] 的形式表示,其中 (x1, y1) 为左下角的坐标,(x2, y2) 是右上角的坐标. 如果相交的面积为正,则称两矩形重叠.需要明确的是,只在 ...