一、CMD和AMD的区别
模块化规范可以认为是 JavaScript 文件之间相互依赖引用的一种通用的语法约定,就是按照一定的规范来写 JavaScript 文件,让它可以方便的被其他 JavaScript 文件引用。
主要有几种常见的规范:
- AMD(Asynchronous Module Definition,异步模块定义)
- CMD(Common Module Definition,通用模块定义)
这两个都是浏览器端的模块加载方案
1.1 AMD规范
AMD(Asynchronous Module Definition)是异步模块定义,采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
在 AMD 规范中,我们使用 define 定义模块,使用 require 加载模块。
定义模块:
define(id?, dependencies?, factory);
// 1.`id` 是定义的模块名,这个参数是 可选的 ,默认值是引入依赖的文件名;
// 2.`dependencies` 是定义的模块中所依赖的 模块数组 ,也是 可选的 ,依赖模块 优先级 执行,并且执行结果按照数组中的排序依次以参数的形式传入 `factory` ;
// 3. `factory` 是模块初始化要执行的函数或对象,是 必需的 。
加载模块:
require([module], callback);
// 1.`module`,数组,里面的成员就是要加载的模块;
// 2.参数 `callback`,则是加载成功之后的回调函数。
优点:
- 适合在浏览器环境中异步加载模块
- 可以并行加载多个模块
缺点:
- 提高了开发成本
- 不符合通用的模块化思维方式
1.2 CMD规范
CMD(Common Module Definition)是公共模块定义,在 CMD 规范中,一个模块就是一个文件。
定义模块:
define(factory);
// 1. 当 `factory` 是一个对象或是一个字符串时,表示该模块的接口就是这个对象或者字符串;
// 2. 当 `factory` 是一个函数时,表示是该模块的构造方法;默认传入三个参数:`require`、`exports`、`module`。其中 `require` 用来加载其它模块,`exports` 用来向外提供模块接口。`module` 是一个对象,存储着与当前模块相关联的一些属性和方法。
加载模块:
seajs.use([module], callback);
优点:可以很容易在 node 中运行
缺点:依赖 SPM 打包,模块的加载逻辑偏重
二、JS是怎么执行的
两个小概念(宏任务和微任务):
1、微任务是指在当前任务执行结束后立即执行的任务;
2、宏任务是指需要排队等待 JavaScript 引擎空闲时才能执行的任务;
我们页面中的js执行顺序是这样的:
第一轮事件循环:
- 主线程执行js整段代码(宏任务),将ajax、setTimeout、promise等回调函数注册到事件队列,并区分宏任务和微任务。
- 主线程提取并执行 事件队列 中的ajax、promise等所有微任务,并注册微任务中的异步任务到 事件队列 。
第二轮事件循环:
- 主线程提取Event Queue 中的第一个宏任务(通常是setTimeout)。
- 主线程执行setTimeout宏任务,并注册setTimeout代码中的异步任务到Event Queue(如果有)。
- 执行Event Queue中的所有微任务,并注册微任务中的异步任务到Event Queue(如果有)。
类似的循环:宏任务每执行完一个,就清空一次事件队列中的微任务。
注意:事件队列中分“宏任务队列”和“微任务队列”,每执行一次任务都可能注册新的宏任务或微任务到相应的任务队列中,只要遵循“每执行一个宏任务,就会清空一次事件队列中的所有微任务”这一循环规则,就不会弄乱。
具体可参考这个 :图解JS执行机制
三、JS是怎么解析的
JavaScript代码编译原理,编译器把程序分解成词法单元(token),然后把词法单元解析成抽象的语法树(AST),再把语法树变成机器指令等待执行。
四、JS是怎么编译的
1.检查语法 2.编译成能在web上运行
五、 angular 是怎么编译的 怎么集成 怎么最后几个文件 angular里面的import 是干嘛用的?
5.1 关于编译
将HTML模板转换为组件树,并生成渲染器,该渲染器用于在运行时将组件树转换为浏览器可以理解的JavaScript代码。在这个过程中,还会将指令、组件和管道编译为渲染器中的可执行代码。
Angular 应用在浏览器中的编译过程通常分为两个阶段:Ahead-of-Time (AOT) 编译(事先编译) 和 Just-In-Time (JIT) 编译(即时编译)。这两种编译方式决定了应用在浏览器中的运行方式。
Ahead-of-Time (AOT) 编译: AOT 编译是一种在构建过程中将 Angular 应用编译成纯JavaScript的方式,以提高应用的性能。在 AOT 编译下,模板在构建时被编译成JavaScript代码,而不是在运行时在浏览器中进行解释和编译。这意味着应用的代码在浏览器中加载时已经是预编译的,因此应用的启动速度更快。
要启用 AOT 编译,你需要在构建时使用 ng build --aot 命令,或者在使用 Angular CLI 创建应用时选择 AOT 编译。
Just-In-Time (JIT) 编译: JIT 编译是一种在运行时将 Angular 应用的模板编译成JavaScript代码的方式。在 JIT 编译下,应用的模板代码在浏览器加载时动态编译,这使得构建过程更快,但可能会导致应用在启动时有一些性能开销。
要使用 JIT 编译,你可以直接使用 ng build 命令构建应用,或者在创建应用时不选择 AOT 编译。
Aot 性能好些
打包后 文件数量减少 是因为模块合并
angular里面的import 是为了引入组件、服务等模块;
六、 promise是改善什么的?
promise是会立即调用的,Promise的回调then,catch是异步。
Promise是一种JavaScript编程语言中用于处理异步操作的机制。
它的主要目的是为了解决回调地狱问题,使异步代码更加可读和可维护。 Promise本身并不是异步,而是一种用于管理异步操作的对象。
- 1.什么是回调地狱?
回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件 - 2.回调地狱的缺点?
不便于阅读
不便于异常处理将异步操作以同步操作的流程表达出来
优点:
- 1.避免了回调地狱,将异步操作以同步操作的流程表达出来
缺点:
- 1.一旦新建它就会立即执行,无法中途取消;
- 2.如果不设置回调函数,Promise内部抛出的错误,不会反应到外部;
- 3.当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成);
七、 主线程只有一个 js为什么只有一个线程
-
历史原因:JavaScript最初是作为一种用于处理网页交互的脚本语言而创建的。在当时的计算机性能和浏览器环境下,多线程执行JavaScript可能会导致不可控的并发问题。因此,JavaScript的设计者选择了单线程模型,以避免潜在的复杂性和问题。
-
安全性:单线程模型可以更容易地实现安全策略,因为它可以防止不同线程之间的竞态条件和共享内存问题。这对于在浏览器中执行不受信任的脚本来说尤为重要,因为它可以防止恶意代码干扰或破坏其他页面的执行。
-
浏览器是单线程的。对DOM的操作需要单线程 不然 若是多线程的话 对同一个节点修改和删除 应该以哪个为主。
八、 怎么打包的 angular
-
Angular CLI整合了Webpack作为构建工具的核心。
-
使用
angular.json配置文件来定义项目的构建配置。在配置文件中,你可以指定项目的入口文件、输出目录、构建环境等信息。 -
当你运行
ng build命令时,Angular CLI会根据配置文件的信息启动构建过程。这个过程包括了读取配置、加载Webpack配置、准备构建环境等步骤。 -
编译器 (Compiler) : Webpack在构建过程中创建一个编译器对象,该对象负责管理整个构建过程,包括分析依赖、应用加载器和插件等。
-
依赖图 (Dependency Graph) : Webpack构建过程中创建了一个依赖图,它记录了模块之间的依赖关系,以确保模块的正确加载顺序。
-
加载器: Webpack使用加载器来处理非JavaScript文件。加载器允许你在构建过程中对模块进行转换,例如,将Sass文件转换为CSS。
-
Webpack分析了项目中的模块依赖关系,了解哪些文件需要被打包,以及它们之间的依赖关系。
-
Webpack本身是一个Node.js应用程序。
九、强类型和弱类型语言的区别
-
强类型语言(Strongly Typed Language) :
- 强类型语言要求变量在使用之前必须明确定义其数据类型,而且在变量的生命周期内不允许改变其数据类型。
- 强类型语言通常会执行严格的类型检查,不允许将不同数据类型的值混合使用,从而防止类型错误。
- 类型错误必须在编译阶段或运行时立即捕获和处理,否则会导致编译错误或运行时异常。
- 强类型语言的例子包括Java、C#、C++等。
-
弱类型语言(Weakly Typed Language) :
- 弱类型语言允许变量在不明确定义数据类型的情况下自由使用,并且可以动态改变其数据类型。
- 弱类型语言通常会执行较少的类型检查,允许混合使用不同数据类型的值,但可能导致潜在的类型错误。
- 类型错误通常不会在编译阶段捕获,而是在运行时才显现,这可能导致一些难以追踪和调试的问题。
- 弱类型语言的例子包括JavaScript、Python、PHP等。
十、Canvas和SVG的区别
Canvas和SVG都是用于在网页上创建图形的技术,但它们有几个关键区别:
-
图像类型:
- Canvas绘制的是位图(bitmap)图形,它是由像素点构成的,因此在放大时会失真。
- SVG绘制的是矢量图(vector)图形,使用数学公式来描述图形,因此可以无损地缩放。
-
性能差异:
- 当需要处理大量节点时,Canvas通常渲染速度较快,因为它处理的是像素级别的数据。
- SVG在处理大量节点时渲染较慢,因为它需要解析和渲染每个矢量图形元素。
-
事件处理:
- SVG支持事件处理器,允许为图形元素添加交互性,例如点击、悬停等。
- Canvas不直接支持事件处理器,需要通过JavaScript手动实现交互。
-
适用范围:
- Canvas适合绘制复杂的动态图像,如图形游戏和数据可视化。
- SVG适合绘制静态或交互性要求不高的图形,如图表、图标和简单的矢量图。
总之,选择Canvas还是SVG取决于项目的需求。Canvas适用于需要高性能绘图和动画的场景,而SVG适用于需要可伸缩且交互性要求较低的图形。
再问一句 Canvas为什么渲染速度快?
1.Canvas在底层使用硬件加速来进行渲染,这意味着它能够更有效地利用计算机的GPU(图形处理单元); 2.
十一、this的指向问题
普通函数是谁调用它就指向谁; 箭头函数本身没有this,在定义的位置 继承父级的this
在三种特殊情境下,this 会 100% 指向 window:
- 立即执行函数(IIFE) //直接执行的匿名函数
- setTimeout 中传入的函数
- setInterval 中传入的函数
十二、call()/bind()/apply()的区别
1.apply、call、bind他们三个都能改变函数this的指向问题;
2.apply、call这两个方法的主动调用,bind返回的是改变this指向后的新函数;
3.传参的问题区别,call和bind都是直接传递参数,apply传递的是数组;
- call的使用
function test(a,b) {
console.log(this) //默认情况下函数中的this指向的是Window对象
console.log(a,b) //a,b对应的是参数1和参数2
}
const obj= {
name:'vivian'
}
test.call(obj,'参数1','参数2') //直接调用函数并改变this的指向
- bind的使用
function test(a,b) {
console.log(this) //默认情况下函数中的this指向的是Window对象
console.log(a,b) //a,b对应的是参数1和参数2
}
const obj= {
name:'vivian'
}
var newFn = test.bind(obj,'参数1','参数2') ;
newFn()
- apply的使用
function test(a,b) {
console.log(this) //默认情况下函数中的this指向的是Window对象
console.log(a,b) //a,b对应的是参数1和参数2
}
const obj= {
name:'vivian'
}
test.apply(obj,['参数1','参数2']) //直接调用函数并改变this的指向