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

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 等等。



原文地址:https://www.cnblogs.com/wiwimi/p/12626523.html

时间: 2025-02-01 17:01:50

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

Vue.js的组件化思想--上

Vue.js的组件化思想--上 一.Vue中的组件 Vue视图层的灵魂 -  组件化 组件(Component)是 Vue.js 最强大的功能之一: 组件可以扩展 HTML 元素,封装可重用的代码: 在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能.在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展. 二.全局组件的创建和注册  全局组件-步骤:1.创建组件Vue.extend(),指定组件的名称--2.注册组件Vue.component()--3.

Vue.js的组件化思想--下

Vue.js的组件化思想--下 一.组件间的通信        组件实例的作用域是孤立的:这意味着不能并且不应该在子组件的模板内直接引用父组件的数据.但是父子组件之间需要通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件.          在 Vue.js 中,父子组件的关系可以总结为 props down, events up .父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息.如下图所示: 二. Prop - 父组件传递数据给子

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

文章大纲 一.项目模块化初步介绍二.项目模块化的两种模式与比较三.大型项目模块化的演进四.项目模块化总结五.参考文章 一.项目模块化初步介绍 1. 前言 在Android开发中,随着项目的不断扩展,项目会变得越来越庞大,而随之带来的便是项目维护成本与开发成本的增加!每次调试时,不得不运行整个项目:每当有新成员加入团队时,需要更多的时间去了解庞大的项目...而为了解决这些问题,团队通常会将项目模块化,以此来降低项目的复杂度和耦合度,让团队可以并行开发与测试,让团队成员更加专注于自己所负责的功能模块

Vue.js的组件化思想 —下

一.组件间的通信          组件实例的作用域是孤立的:这意味着不能并且不应该在子组件的模板内直接引用父组件的数据.但是父子组件之间需要通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件.          在 Vue.js 中,父子组件的关系可以总结为 props down, events up .父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息.如下图所示: 二. Prop — 父组件传递数据给子组件          pr

互联网公司为什么那么喜欢问多线程的面试:15道面试题带你了解

对于这些专题的详解,专门做了一个983页的PDF版本,如下 (更多完整项目下载.未完待续.源码.图文知识后续上传github.)可以点击关于我联系我获取 1)现在有 T1.T2.T3 三个线程,你怎样保证 T2 在 T1 执行完后执行,T3 在 T2 执行完后执 行? 这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉.这个多线程问题比较简单,可以用 join 方法实现. 2)在 Java 中 Lock 接口比 synchronized 块的优势是什么?你需要

vue组件化编程

一:vue项目目录 build : webpack.base.conf.js : config --> index.js 二:组件化编程相关文件分析 1.主页面 index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initi

前端工程化,模块化,组件化

前端工程化是根据业务特点,将前端开发流程规范化,标准化,它包括了开发流程,技术选型,代码规范,架构发布等等 用于提升前端工程师的开发效率和代码质量 工程化是一种思想 >模块化 组件化是工程化这种思想的具体体现,模块化最直观的就是代码复用,每个模块都能提供接口,供其他页面或者模块互相调用,比如封装一个轮播图,写淘宝的时候可以饮用进来,写京东的时候也可以调用不同的接口,传入不同的参数饮用进来 >模块化实现 1.函数形式 2.命名空间形式 3.立即执行函数 4.模式增强 >组件化 组件化可以看

Android--开发:由模块化到组件化

在Android SDK一文中,我们谈到模块化和组件化,现在我们来聊聊组件化开发背后的哪些事.最早是在广告SDK中应用组件化,但是同样适用于普通应用开发 以下高能,请做好心理准备,看不懂请发私信来交流.本文不推荐新手阅读,如果你刚接触Android开发不久,请立刻放弃阅读本文. 模块化和组件化 模块化 组件化不是个新概念,其在各行各业都一直备受重视.至于组件化什么时候在软件工程领域提出已经无从考究了,不过呢可以确认的是组件化最早应用于服务端开发,后来在该思想的指导下,前端开发和移动端开发也产生各

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

模块化和组件化 模块化 组件化不是个新概念,其在各行各业都一直备受重视.至于组件化什么时候在软件工程领域提出已经无从考究了,不过呢可以确认的是组件化最早应用于服务端开发,后来在该思想的指导下,前端开发和移动端开发也产生各自的开发方式. 在了解组件化之前,先来回顾下模块化的定义 Modular programming is a software design technique that emphasizes separating the functionality of a program in