此文章,来源于印客学院的资料【第一部分:基础篇(105题)】,也有一些从网上查找的补充。
这里只是分享,便于学习。
诸君可以根据自己实际情况,自行衡量,看看哪里需要加强。
概述如下:
- 模块化开发怎么做?
- 异步加载JS的方式有哪些?
- 那些操作会造成内存泄漏?
- XML和JSON的区别?
- 谈谈你对webpack的看法
- 说说你对AMD和Commonjs的理解
- 常见web安全及防护原理
- 用过哪些设计模式?
- 为什么要有同源限制?
- offsetWidth/offsetHeight,clientWidth/clientHeight与scrollWidth/scrollHeight的区别
模块化开发怎么做?
立即执行函数,不暴露私有成员
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0vS9jVJl-1689732980409)(https://mmbiz.qpic.cn/sz_mmbiz_png/BOlSgLkrCDbNK7y5xraRyQHGdDibibdWr6Ms2ICYLB9mgibGcGJImqoicYGzx0RjGAZw0dY6zmcdibgAALjpc6gYaoQ/640?wx_fmt=png)]
在 JavaScript 中,模块化开发是一种将代码分割为独立模块的方法,每个模块都有自己的作用域,并且可以通过导入和导出来与其他模块进行交互。这种模块化的方式有助于提高代码的可维护性、重用性和可测试性。
下面是一种常见的 JavaScript 模块化开发方式,使用 ES6 的模块语法:
- 创建一个模块(例如,math.js):
// math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
- 导入并使用模块中的函数:
// main.js
import { add, subtract } from './math.js';
console.log(add(5, 2)); // 输出: 7
console.log(subtract(5, 2)); // 输出: 3
在这个例子中,math.js
是一个模块,它定义了 add()
和 subtract()
两个函数,并通过 export
关键字导出。然后,在 main.js
中使用 import
关键字将需要的函数导入,并进行调用。
请注意,上述示例假设你正在使用支持 ES6 模块化的环境,比如现代浏览器或者 Node.js 12.0.0+ 版本。如果你想在不同环境或旧版浏览器中使用模块化开发,可能需要使用工具(如Webpack、Browserify)或降级到其他的模块化方案(如CommonJS、AMD)。
此外,还有其他的模块化规范和库可供选择,例如 CommonJS(Node.js 默认的模块化方案)、AMD(用于浏览器中异步加载模块)、UMD(通用模块定义)等。选择合适的模块化方案取决于你的项目需求和目标环境。
异步加载JS的方式有哪些?
JavaScript 中异步加载 JS 的方式有以下几种常见的方法:
- 动态创建
<script>
标签:通过 JavaScript 动态创建<script>
标签,并将其添加到页面中,从而异步加载指定的 JS 文件。
var script = document.createElement('script');
script.src = 'path/to/script.js';
document.head.appendChild(script);
- 使用
async
和defer
属性:在 HTML 中的<script>
标签上可以设置async
或defer
属性以实现异步加载。
async
:脚本文件的加载和执行不会阻塞页面的解析和渲染。脚本加载完成后立即执行。
<script src="path/to/script.js" async></script>
defer
:脚本文件的加载也不会阻塞页面的解析和渲染,但脚本执行会在页面解析完毕后进行(DOMContentLoaded 事件之前)。
<script src="path/to/script.js" defer></script>
- 使用模块化加载器(例如 RequireJS、SystemJS):这些工具提供了更强大的模块化功能,支持异步加载模块。
require(['path/to/module'], function(module) {
// 模块加载完成后执行的回调函数
});
- 使用动态 import():ES6 引入了动态
import()
方法,可以异步加载模块并返回一个 Promise 对象。
import('path/to/module')
.then(function(module) {
// 模块加载完成后执行的回调函数
});
这些方式都可以实现异步加载 JS 文件,具体选择哪种方式取决于你的项目需求和目标环境。需要注意的是,动态创建 <script>
标签、async
和 defer
属性适用于旧版浏览器和现代浏览器,而模块化加载器和动态 import()
方法则需要考虑目标环境的支持情况。
那些操作会造成内存泄漏?
在 JavaScript 中,以下几种情况可能导致内存泄漏:
-
无限制地添加事件监听器:如果在 DOM 元素上添加了事件监听器,但没有正确地移除它们,就会导致内存泄漏。这意味着即使元素已经被移除,相关的事件处理函数仍然存在于内存中,无法被回收。
-
循环引用:JavaScript 中的对象通过引用进行内存管理。如果存在循环引用,即对象 A 引用对象 B,而对象 B 又引用对象 A,那么这两个对象将 无法被垃圾回收机制正常回收,从而造成内存泄漏。
function createObjects() {
var objA = {};
var objB = {};
objA.someProperty = objB;
objB.anotherProperty = objA;
// objA 和 objB 形成了循环引用
}
createObjects();
- 定时器和回调函数未清理:如果使用定时器或设置回调函数,但忘记清除它们,那么定时器或回调函数会持续占用内存,并且可能导致其他相关资源无法被释放。
function startTimer() {
setInterval(function() {
// ...
}, 1000);
}
startTimer();
-
巨大的数据结构:如果创建了大量的对象、数组或其他数据结构,并且不再需要时没有及时释放它们,就会占用大量的内存并导致内存泄漏。
-
闭包:如果在函数内部创建了闭包,并且闭包引用了外部函数的变量,即使外部函数执行完毕,闭包仍然保留对这些变量的引用,从而导致内存泄漏。
function createClosure() {
var data = 'sensitive information';
return function() {
// 使用 data 变量
console.log(data);
};
}
var leakedFunction = createClosure();
// 外部函数 createClosure 已经执行完毕,但由于闭包的存在,data 变量无法被正常释放
为避免内存泄漏,需要确保正确地管理事件监听器
、清除定时器
和回调函数
、避免循环引用
以及及时释放不再使用的对象和数据结构
等。
必要时可以使用工具和技术进行性能分析和内存泄漏检测。
XML和JSON的区别?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BiVe0F09-1689732980411)(https://mmbiz.qpic.cn/sz_mmbiz_png/BOlSgLkrCDbNK7y5xraRyQHGdDibibdWr6Jpu0k22V3kpFdz6ZK6lxVrArFVfVCbt4k7ncWQGV4J24QLFqvrhj5g/640?wx_fmt=png)]
XML(可扩展标记语言)和JSON(JavaScript对象表示)是两种常用的数据交换格式,
它们有以下区别:
-
语法:XML使用自定义的标签和属性来表示数据结构,而JSON使用简洁的键值对形式表示。因此,XML的结构更加繁琐,而JSON更加紧凑易读。
-
数据类型支持:XML支持多种数据类型,包括文本、数字、布尔值等,而JSON仅支持字符串、数字、布尔值、数组和对象这几种基本数据类型。
-
可读性:由于XML使用了自定义标签和属性,使得它比JSON在结构上更加易读。同时,XML可以通过注释和文档类型定义(DTD或XSD)来提供更多的描述和文档结构。
-
解析和处理:由于XML的语法比较复杂,解析XML文件需要更多的计算资源和时间,而JSON的解析速度更快,通常比XML更高效。
-
扩展性:XML具有很强的扩展性,可以通过定义自己的标签和属性来适应不同的数据结构。而JSON的扩展性相对较弱,只能使用现有的数据类型。
总体而言,XML适用于复杂结构和较大规模的数据交换,而JSON适用于简单结构和较小规模的数据交换。
选择使用哪种格式取决于具体的需求和应用场景。
谈谈你对webpack的看法
Webpack是一个现代化的前端打包工具,它在前端开发中扮演着非常重要的角色,你可以使用 WebPack 管理你的模块依赖, 并编绎输出模块们所需的静态文件。
它能够很好地管理 、打包 Web 开发中所用到的 HTML 、Javascript 、 CSS 以及各种静态文件 ( 图片 、字体等), 让开发过程更加高效。
对于不同类型的资源, webpack 有对应的模块加载器 。 webpack 模块打包器会分析模块间的依赖关系, 最后 生成了优化且合并后的静态资源。
对Webpack有以下几点看法:
-
模块化打包:Webpack可以将前端项目中的各种资源(例如JavaScript、CSS、图片等)都视为模块,并利用模块化的方式进行打包。这使得我们可以使用import、export等语法来组织代码,提高代码的可维护性和复用性。
-
自动化构建:Webpack提供了丰富的插件系统,可以自动化地完成一些构建任务,例如代码压缩、文件合并、优化等。通过配置Webpack,我们可以在开发过程中自动完成这些繁琐的工作,提高开发效率。
-
资源优化:Webpack支持各种优化功能,例如代码分割、异步加载、懒加载等。这些优化策略可以减小打包文件的体积,加快网页加载速度,提升用户体验。
-
生态丰富:Webpack有庞大的开发社区,有许多插件和工具可以与其配合使用,解决各种开发需求。同时,Webpack也能和其他流行的前端框架(如React、Vue等)无缝集成,提供更好的开发体验。
-
配置复杂:对于初学者来说,Webpack的配置可能会比较复杂。Webpack提供了非常灵活的配置选项,但这也意味着需要一定的学习和理解成本。然而,一旦掌握了Webpack的核心概念和配置方式,就能发挥其强大的功能。
总的来说,Webpack是一个功能强大且灵活的前端打包工具,它可以帮助我们优化项目结构、提高开发效率和网页性能。
尽管配置可能相对复杂,但通过学习和实践,Webpack可以成为前端开发中不可或缺的一部分。
说说你对AMD和Commonjs的理解
AMD(Asynchronous Module Definition)和CommonJS是两种主要的模块化规范,用于在JavaScript中组织和管理模块代码。
对它们的理解如下:
-
AMD(异步模块定义):
- 异步加载:AMD规范支持异步加载模块,允许模块在需要时动态加载,不会阻塞其他代码的执行。
- 浏览器环境:AMD主要用于浏览器端,能够通过异步加载提高前端应用的性能和加载速度。
- define函数:AMD使用define函数来定义模块,该函数接受模块的依赖列表和回调函数作为参数,当所有依赖加载完成后,回调函数被执行。
-
CommonJS:
- 同步加载:CommonJS规范采用同步加载模块的方式,在加载模块时会阻塞后续代码的执行,直到模块加载完成。
- 服务器环境:CommonJS主要用于服务器端,例如Node.js,它适用于同步I/O操作的环境。
- require方法:CommonJS使用require方法来加载模块,并通过exports对象暴露模块的公共接口。
AMD和CommonJS都解决了JavaScript代码模块化的问题,但是它们在语法和加载方式上有所区别,因此在不同的环境和应用场景中会有不同的使用情况。
一般来说,AMD适用于浏览器环境和异步加载的需求,而CommonJS适用于服务器环境和同步加载的需求。
同时,值得注意的是,在现代前端开发中,ES6模块化也已经成为了主流,它在语法和功能上都有所改进,可以逐渐取代AMD和CommonJS
。
常见web安全及防护原理
常见的Web安全问题包括以下几个方面,同时也提供了相应的防护原理:
-
跨站脚本攻击(XSS):
- 防护原理:对用户输入进行有效的输入验证和过滤,使用安全的编码方式对输出进行处理(如HTML转义),使用HTTP头中的Content Security Policy(CSP)设置白名单策略,限制页面资源加载等。
-
跨站请求伪造(CSRF):
- 防护原理:使用CSRF令牌(Token)验证用户发起的请求,确保请求是合法的,同时设置SameSite属性,禁止浏览器在跨域请求中携带Cookie。
-
注入攻击(包括SQL注入、OS命令注入等):
- 防护原理:使用参数化查询或预编译语句来构建SQL查询,避免使用拼接字符串的方式。对用户输入进行严格的输入验证和过滤,使用参数绑定或转义来防止OS命令注入。
-
敏感数据泄露:
- 防护原理:对敏感数据进行加密存储,使用HTTPS协议进行数据传输,确保通信的机密性和完整性。限制敏感数据的访问权限,实施访问控制策略。
-
常见漏洞(如未授权访问、文件上传漏洞等):
- 防护原理:实施严格的身份认证和授权机制,限制用户的访问权限。对用户上传的文件进行合法性检查,限制上传文件的类型和大小,避免恶意文件的执行。
-
点击劫持:
- 防护原理:使用X-Frame-Options或Content Security Policy(CSP)设置禁止在iframe中加载网站内容,或者使用frame-busting代码阻止网页被嵌套。
-
DDOS攻击:
- 防护原理:使用反向代理和负载均衡技术分散流量,配置网络设备防火墙和入侵检测系统来过滤恶意流量,使用CDN(内容分发网络)减轻服务器负载。
综上所述,Web安全的防护原理包括良好的输入验证和过滤、安全编码实践、合适的身份认证和授权机制、合适的加密传输、限制访问权限、使用安全的框架和库等。
同时,定期进行漏洞扫描和安全审计,及时更新和修复系统漏洞也是保障Web应用安全的重要措施。
XSS与CSRF有什么区别吗?
XSS是获取信息,不需要提前知道其他用户⻚⾯的代码和数据包 。 CSRF 是代替用户完成指定的动作, 需要知道其他用户⻚⾯的代码和数据包。
要完成⼀次 CSRF 攻击, 受害者必须依次完成两个步骤
- 登录受信任网站 A , 并在本地生成 Cookie
- 在不登出 A 的情况下, 访问危险网站 B
CSRF的防御
服务端的 CSRF 方式方法很多样,但总的思想都是⼀致的,就是在客户端页面增加伪随机数,通过验证码的方法。
用过哪些设计模式?
在JavaScript中,有许多常用的设计模式。以下是一些常见的设计模式及其示例:
-
单例模式(Singleton Pattern):
示例:实现全局唯一的日志记录器。const Logger = (function() { let instance; function init() { // 私有方法和属性 function log(message) { console.log(message); } // 公有方法和属性 return { log: log }; } return { getInstance: function() { if (!instance) { instance = init(); } return instance; } }; })(); const logger = Logger.getInstance(); logger.log("Hello, world!");
-
工厂模式(Factory Pattern):
示例:创建不同类型的产品。function Product(name, price) { this.name = name; this.price = price; } function ProductFactory() { this.createProduct = function(type) { switch (type) { case "A": return new Product("Product A", 100); case "B": return new Product("Product B", 200); default: return null; } }; } const factory = new ProductFactory(); const productA = factory.createProduct("A"); console.log(productA); const productB = factory.createProduct("B"); console.log(productB);
-
观察者模式(Observer Pattern):
示例:实现一个事件订阅发布机制。function Publisher() { this.subscribers = []; this.subscribe = function(subscriber) { this.subscribers.push(subscriber); }; this.unsubscribe = function(subscriber) { const index = this.subscribers.indexOf(subscriber); if (index !== -1) { this.subscribers.splice(index, 1); } }; this.publish = function(message) { this.subscribers.forEach(function(subscriber) { subscriber.notify(message); }); }; } function Subscriber(name) { this.name = name; this.notify = function(message) { console.log(this.name + ": " + message); }; } const publisher = new Publisher(); const subscriberA = new Subscriber("Subscriber A"); const subscriberB = new Subscriber("Subscriber B"); publisher.subscribe(subscriberA); publisher.subscribe(subscriberB); publisher.publish("Hello, subscribers!");
-
发布/订阅模式(Publish/Subscribe Pattern):
示例:使用第三方库(如EventEmitter)实现自定义事件的发布和订阅。const EventEmitter = require("events"); const eventEmitter = new EventEmitter(); // 订阅事件 eventEmitter.on("myEvent", function(message) { console.log("Event received: " + message); }); // 发布事件 eventEmitter.emit("myEvent", "Hello, subscribers!");
这些只是JavaScript中的一些常见设计模式及其示例。
在实际开发中,根据具体需求选择合适的设计模式可以提高代码的可维护性和扩展性。
为什么要有同源限制?
JavaScript的同源策略是一种安全机制,用于保护用户隐私和防止恶意网站对用户数据进行滥用。
同源策略要求在浏览器中运行的JavaScript代码,只能与来自 同一源(即协议、域名和端口号都相同) 的页面进行交互,而不能与不同源的页面进行直接的读写操作。
同源策略的主要限制有以下几点:
- 无法通过JavaScript访问不同源的文档对象模型(DOM)。
- 无法通过JavaScript获取不同源页面的Cookie、LocalStorage或SessionStorage等数据。
- 无法通过XMLHttpRequest或Fetch等网络请求对象直接向不同源的服务器发送请求。
这些限制主要是为了防止恶意脚本窃取用户敏感信息,并阻止跨站点请求伪造攻击(CSRF)等安全威胁。
同时,浏览器提供了一些机制来允许跨域资源共享(CORS)和在特定情况下放宽同源策略的限制。
举例说明: 比如⼀个黑客程序,他利用 Iframe 把真正的银⾏登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过 Javascript 读取到你的表单中 input 中的内容, 这样用户名,密码就轻松到手了。
为了解决跨域问题,常见的方法包括:
- JSONP(JSON with Padding):利用script标签的src属性没有同源限制的特性,通过动态创建script标签来加载跨域的JavaScript资源。
- CORS(Cross-Origin Resource Sharing):在服务器端设置响应头,允许特定的跨域请求。
- 代理服务器:在同源的服务器上设置一个代理,实际发送和接收跨域请求。
需要注意的是,绕过同源策略可能会带来安全风险。因此,在开发过程中应合理设计接口和权限控制,并遵循最佳安全实践。
offsetWidth/offsetHeight,clientWidth/clientHeight与scrollWidth/scrollHeight的区别
在JavaScript中,offsetWidth、offsetHeight、clientWidth、clientHeight、scrollWidth和scrollHeight都是用于获取元素的尺寸信息的属性,但它们有着不同的含义和用途。
-
offsetWidth和offsetHeight:
- offsetWidth:元素在水平方向上的完整宽度,包括内容宽度、内边距和边框宽度。
- offsetHeight:元素在垂直方向上的完整高度,包括内容高度、内边距和边框宽度。
注:offsetWidth和offsetHeight是只读属性。
-
clientWidth和clientHeight:
- clientWidth:元素的可见区域的宽度,不包括滚动条、边框和外边距。
- clientHeight:元素的可见区域的高度,不包括滚动条、边框和外边距。
注:clientWidth和clientHeight是只读属性。
-
scrollWidth和scrollHeight:
- scrollWidth:元素内容的实际宽度,包括被隐藏的内容,不包括内边距和边框。
- scrollHeight:元素内容的实际高度,包括被隐藏的内容,不包括内边距和边框。
注:scrollWidth和scrollHeight是只读属性。
这些属性在处理元素布局、计算滚动区域以及响应式设计等方面非常有用。需要注意的是,这些属性的值通常是以像素为单位的整数,且可能会受到盒模型、浏览器差异和CSS样式等因素的影响。
- offsetWidth/offsetHeight 返回值包含content + padding + border,效果与e.getBoundingClientRect()相同
- clientWidth/clientHeight 返回值只包含content + padding, 如果有滚动条,也不包含滚动条
- scrollWidth/scrollHeight 返回值包含content + padding + 溢出内容的尺寸