1、 同步和异步的区别
同步:在同步操作中,代码按照顺序一步步执行,当前操作完成后才会进行下一个操作。也就是说,在进行某个操作时,程序会阻塞,直到该操作完成后才会继续执行下面的代码。同步操作通常会等待操作完成并立即返回结果。
异步:在异步操作中,代码不会等待某个操作的完成,而是会继续执行后续的代码。异步操作通常会在后台启动一个任务或者事件,并且可以继续执行其他操作而无需等待该任务或事件的完成。当任务或事件完成后,系统会通知相应的回调函数或事件处理器。
事件循环机制与同步异步的关系
事件循环机制是用于处理异步操作的执行和回调的一种机制。它提供了一种机制来管理和调度异步任务的执行顺序,确保在适当的时候执行回调函数或事件处理器。
在事件循环机制中,异步操作将被添加到事件队列中,然后事件循环会不断地从队列中取出事件,并按照顺序依次执行相应的回调函数或事件处理器。这样可以实现非阻塞的异步执行,避免了同步操作中可能造成的阻塞问题。
在事件循环机制中,异步操作可以使用回调函数、Promise、async/await等方式来处理。通过使用事件循环机制,可以以非阻塞的方式处理异步任务,提高程序的性能和响应能力。
异步任务分为微任务和宏任务:
微任务:
是指在JavaScript事件循环的宏任务(Macrotask)执行完成后,被添加到微任务队列中的任务。微任务会在当前宏任务执行结束之后、下一个宏任务开始之前执行
触发条件:
- Promise的回调函数:当Promise对象状态变为已解决(fulfilled)或已拒绝(rejected)时,相关的回调函数会作为微任务被添加到微任务队列中执行。
- MutationObserver的回调函数:当观察的DOM发生变化时,MutationObserver的回调函数会以微任务方式执行。
- process.nextTick(Node.js环境):process.nextTick方法可以将回调函数作为微任务直接执行。
宏任务
是指在JavaScript事件循环中被添加到宏任务队列中的任务
包含几种情况:
- setTimeout和setInterval:使用定时器函数创建的任务会在指定的时间间隔后被添加到宏任务队列中执行。
- I/O操作:例如读取文件、发送网络请求等异步操作会生成对应的宏任务,当相应的I/O操作完成后,相关的回调函数会被添加到宏任务队列中执行。
- 用户交互事件:例如鼠标点击、键盘输入等用户交互行为会触发对应的宏任务。
- 延迟执行代码:例如通过script标签加载的外部JavaScript文件会作为宏任务进行执行。
执行顺序:
先执行同步代码,
遇到异步宏任务则将异步宏任务放入宏任务队列中,
遇到异步微任务则将异步微任务放入微任务队列中,
当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,
微任务执行完毕后再将异步宏任务从队列中调入主线程执行,
一直循环直至所有任务执行完毕。
2、谈一谈箭头函数与普通函数的区别
- 箭头函数比普通函数更加简洁
- 箭头函数没有自己的this
- 箭头函数继承来的this永远不会改变
- 箭头函数不能走为构造函数
- 箭头函数没有arguments
- call,bind,apply无法改变this指向
call,bind,apply区别
bind、call、apply 都是 JavaScript 中用于改变函数执行上下文的方法,它们的主要区别在于参数传递方式和函数调用的时机:
call 和 apply:改变函数执行时的上下文,并立即执行该函数。它们的第一个参数都是指定的函数执行上下文,区别在于传递给函数的参数的方式不同。call 会将参数逐个传递,而 apply 则会将参数放在数组中传递。
bind:返回一个新函数,并将原函数的执行上下文改变为绑定的对象。不同于 call 和 apply,bind 不会立即执行原函数,而是返回一个新的函数,需要手动调用这个新的函数才能执行。
实现bind三步
修改this指向
动态传递参数
兼容new关键字
3、 JS 数组和对象的遍历方式,以及几种方式的比较
-
for 循环:
-
适用于遍历数组和对象
-
可以通过索引或键来访问数组或对象的元素
-
比较灵活,可以根据需要自定义遍历顺序和步长
-
需要手动控制循环变量和循环条件
-
-
for…of 循环(只适用于数组):
- 用于遍历数组中的元素。
- 提供了一种简洁的语法来遍历数组,无需手动管理索引。
- 不能直接用于遍历对象,需要先将对象转换为数组再进行遍历
-
for…in 循环(只适用于对象):
- 用于遍历对象的可枚举属性。
- 遍历顺序可能不确定,不适用于强依赖遍历顺序的情况。
- 对于数组来说,会遍历数组的索引而非元素本身,因此不推荐用于数组的遍历
-
Array.forEach() 方法(只适用于数组):
- 提供了一种简洁的方式来遍历数组。
- 对数组的每个元素都执行一个回调函数,无需手动管理索引。
- 无法中途跳出循环或进行其他控制操作。
-
Object.keys() 和 Object.values() 方法(只适用于对象):
- Object.keys(obj) 返回一个由对象的可枚举属性组成的数组。
- Object.values(obj) 返回一个由对象的可枚举属性值组成的数组。
- 可以将上述方法结合 for…of 循环来遍历对象的键和值。
4、如何解决跨域问题
-
通过jsonp跨域
-
nginx代理跨域
-
nodejs中间件跨域
-
后端在头部信息中设置安全域名
-
前端代理
JSONP的原理:
假设有两个域名:域名A和域名B。网页所在的域名A需要从域名B获取数据,而域名B与域名A不在同一个源。
在域名A的网页中,创建一个
<script>
标签,并将其src
属性设置为域名B的API地址,并传递一个回调函数参数,
例如:
<script src="http://domainB.com/api?callback=callbackFunction"></script>
。域名B的服务器接收到请求后,将数据作为参数传递给回调函数,并返回一个JavaScript函数的调用,
例如:callbackFunction({data: ...});
。域名A的网页中定义了回调函数
callbackFunction
,当<script>
标签加载完成后,回调函数即被执行,并可以获取到域名B返回的数据。这样,域名A就能够通过回调函数获取到域名B的数据,实现跨域数据的获取。
同源策略(Same-Origin Policy)
是浏览器中一种基本的安全机制,用于限制不同源之间的访问,以防止恶意网站对用户信息的窃取或篡改。
同源指的是三个要素相同:协议(Protocol)、域名(Domain)和端口(Port)。只有当两个URL的协议、域名和端口完全相同,才满足同源要求。
同源策略的原则如下:
安全性:浏览器不允许通过脚本获取或修改来自其他源的敏感数据。这样可以有效防止跨站点脚本攻击(XSS)。
隔离性:不同源的页面之间应该相互隔离,不能互相干扰或访问彼此的资源。
在同源策略下,以下操作受到限制:
DOM访问:JavaScript无法通过
document
或window
对象访问其他源的DOM元素。Cookie、LocalStorage和SessionStorage访问:浏览器不会发送包含Cookie等验证信息的请求给其他源,也无法通过JavaScript读取其他源的这些信息。
XMLHttpRequest/Fetch请求:默认情况下,浏览器不允许跨源发起AJAX请求,即XMLHttpRequest或Fetch API只能向同源地址发送请求。
跨窗口通信:不同源的页面之间无法直接通过JavaScript进行通信。
为了克服同源策略的限制,可以使用以下方法:
跨域资源共享(CORS):服务器端通过添加响应头来允许特定源的跨域请求。
JSONP:利用
<script>
标签通过回调函数获取跨域数据。代理:通过服务器端转发请求来实现跨域访问。
postMessage API:在不同窗口/文档之间进行安全的跨源消息传递。
需要注意的是,同源策略只存在于浏览器中,而对于服务器端来说,不存在同源策略的限制。服务器端可以自由地访问不同源的资源。
为什么img和link不用配置跨域
img标签和link标签之所以不需要配置跨域,是因为它们在设计时就具有了跨域访问的能力和相应的安全机制。
对于img标签来说,它用于加载并显示图片资源。浏览器允许通过img标签引用其他源的图片资源,并将其显示在页面上。这是由于图片资源本身不具有与页面进行交互的能力,也没有访问页面上其他元素的权限,因此不会带来安全风险。
而link标签主要用于加载样式表文件(CSS文件)。当浏览器解析HTML文档时,会根据link标签中指定的URL去请求对应的CSS文件。同样地,由于CSS文件只包含样式信息,不具有与页面进行交互的能力,因此浏览器允许通过link标签引用其他源的CSS文件。
需要注意的是,尽管img标签和link标签不需要特殊配置跨域,但它们在请求其他源的资源时仍然受到浏览器的同源策略的限制。例如,在加载图片资源时,如果图片所在的源与当前页面的源不同,浏览器会发送CORS(跨域资源共享)请求来验证是否允许跨域访问该图片。如果服务器端返回适当的响应头,浏览器就会允许该跨域请求顺利完成。
总结来说,img标签和link标签之所以不用配置跨域,是因为它们本身的设计就符合浏览器的同源策略,并且只用于加载资源而无法执行与页面交互的操作。
为什么要配置跨域
跨域访问是指在浏览器中,当前页面的域名、端口或协议与请求的资源所在的域名、端口或协议不一致。浏览器的同源策略会限制这种跨域的访问,默认情况下,跨域请求是被禁止的。然而,在某些情况下,我们需要实现跨域访问,这时候就需要进行跨域配置。
会用到跨域的场景
- AJAX请求
- 跨域资源共享
- 跨域嵌入资源
- 跨域字体使用
- 跨文档通信
5、 XML和JSON的区别
XML(可扩展标记语言)和JSON(JavaScript对象表示法)是两种常用的数据交换格式,它们在结构和用途上有一些区别。
-
结构:XML使用自定义的标签和属性来表示数据,类似于HTML,具有较为繁琐的结构。而JSON使用键值对的方式表示数据,更加简洁明了。
-
可读性:XML采用纯文本格式,具有良好的可读性,容易阅读和理解。而JSON也是文本格式,相对于XML更加紧凑,但仍然具有较高的可读性。
-
数据类型:XML支持多种数据类型,包括字符串、数字、布尔值、日期等,可以更灵活地表示数据。JSON主要支持基本的数据类型,如字符串、数字、布尔值,还可以表示数组和对象结构。
-
解析和处理:由于XML的结构比较复杂,解析和处理XML数据需要使用特定的解析器,例如DOM(文档对象模型)和SAX(简单API for XML)。而JSON具有更简单的结构,大部分编程语言都内置了对JSON的解析和处理支持,使得操作更加方便。
-
扩展性:XML通过使用DTD(文档类型定义)或XSD(XML Schema定义)来定义数据结构,并支持命名空间的概念,可以进行较为复杂的数据验证和扩展。JSON在结构上相对简单,没有内置的验证机制,扩展性较弱。
综上所述,XML适合表示复杂结构和需要进行严格数据验证的场景,而JSON更加简洁、易于解析和处理,适用于大部分数据交换和存储的需求。选择使用XML还是JSON取决于具体的应用场景和需求。
6、谈谈你对webpack的看法
Webpack 是一个 静态模块打包器,可以分析各个模块的依赖关系,项目中的所有资源皆为模块,通过分析模块间的依赖关系,在其内部递归构建出一个依赖关系图,其中包含应用程序需要的每个模块,然后将这些模块打包成一个或多个 bundle。最终编绎输出模块为 HTML、JavaScript、CSS 以及各种静态文件(图片、字体等)。
webpack 就像一条生产线,要经过一系列处理流程(loader)后才能将源文件转换成输出结果。 这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理
插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。 webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作。
webpack的主要作用如下:
模块打包 可以将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序。利用打包我们就可以在开发的时候根据我们自己的业务自由划分文件模块,保证项目结构的清晰和可读性。
编译兼容 在前端的“上古时期”,手写一堆浏览器兼容代码一直是令前端工程师头皮发麻的事情,而在今天这个问题被大大的弱化了,通过webpack的Loader机制,不仅仅可以帮助我们对代码做polyfill,还可以编译转换诸如.less,.vue,.jsx这类在浏览器无法识别的格式文件,让我们在开发的时候可以使用新特性和新语法做开发,提高开发效率。
能力扩展 通过webpack的Plugin机制,我们在实现模块化打包和编译兼容的基础上,可以进一步实现诸如按需加载,代码压缩等一系列功能,帮助我们进一步提高自动化程度,工程效率以及打包输出的质量。
插件和加载器有什么区别
常见的插件:HtmlWebpackPlugin,MiniCssExtractPlugin
常见的加载器:ts-loader,vue-loader
在Webpack中,插件(plugins)和加载器(loaders)是两个不同的概念,用于处理不同的任务。
插件(plugins):
- 插件是Webpack的扩展模块,用于执行更广泛的任务和自定义构建流程。
- 插件可以实现各种功能,例如优化输出、资源管理、环境变量注入、代码分割等。
- 插件通过在Webpack构建过程的特定点进行钩子函数调用来工作。
- 插件使用JavaScript编写,并通过Webpack的插件机制进行注册和调用。
加载器(loaders):
- 加载器是用于处理特定类型的文件的转换工具,将源文件转换为Webpack可识别的模块。
- 加载器能够在导入模块时对其进行预处理,比如将CSS文件转换为JavaScript模块或将ES6代码转换为ES5代码等。
- 加载器按照从右到左的顺序链式调用,每个加载器都将对文件进行转换,并将结果传递给下一个加载器。
- 加载器可以在Webpack配置中指定,并通过模块规则(module rules)来匹配特定的文件类型。
总结:
- 插件用于执行更广泛的任务和自定义构建流程,能够改变Webpack的工作方式和输出结果。
- 加载器用于处理特定类型的文件,将它们转换为Webpack可识别的模块,以便在构建过程中使用。
插件和加载器在Webpack配置中起着不同的作用,在实际应用中常常结合使用,以满足项目的需求。