1, 简单谈一下 cookie ?
cookie 是服务器提供的一种用于维护会话状态信息的数据,通过服务器发送到浏览器,浏览器保存在本地,当下一次有同源的请求时,将保存的 cookie 值添加到请求头部,发送给服务端。这可以用来实现记录用户登录状态等功能。cookie 一般可以存储 4k 大小的数据,并且只能够被同源的网页所共享访问。
服务器端可以使用 Set-Cookie 的响应头部来配置 cookie 信息。一条 cookie 包括了 5 个属性值 expires、domain、path、secure、HttpOnly。 其中 expires 指定了 cookie 失效的时间, domain 是域名、 path 是路径,domain 和 path 一起限制了 cookie 能够被哪些 url 访问。 secure 规定了 cookie 只能在确保安全的情况下传输, HttpOnly 规定了这个 cookie 只能被服务器访问,不能使用 js 脚本访问。
2 ES6 模块与 CommonJS 模块、AMD、CMD 的差异。
它们之间的主要区别有两个方面。
(1)第一个方面是在模块定义时对依赖的处理不同。AMD 推崇依赖前置,在定义模块的时候就要声明其依赖的模块。而 CMD 推崇就近依赖,只有在用到某个模块的时候再去 require。
(2)第二个方面是对依赖模块的执行时机处理不同。首先 AMD 和 CMD 对于模块的加载方式都是异步加载,不过它们的区别在于模块的执行时机,AMD 在依赖模块加载完成后就直接执行依赖模块,依赖模块的执行顺序和我们书写的顺序不一定一致。而 CMD 在依赖模块加载完成后并不执行,只是下载而已,等到所有的依赖模块都加载好后,进入回调函数逻辑,遇到 require 语句的时候才执行对应的模块,这样模块的执行顺序就和我们书写的顺序保持一致了。
3 ES6 模块与 CommonJS 模块
1.CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。 ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令 import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
2.CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。 CommonJS 模块就是对象,即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。 而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
4. requireJS 的核心原理是什么?(如何动态加载的?如何避免多次加载的?如何 缓存的?)
require.js 的核心原理是通过动态创建 script 脚本来异步引入模块,然后对每个脚本的 load 事件进行监听,如果每个脚本都加载完成了,再调用回调函数。
5. documen.write 和 innerHTML 的区别?
document.write 的内容会代替整个文档内容,会重写整个页面。
innerHTML 的内容只是替代指定元素的内容,只会重写页面中的部分内容。
6,innerHTML 与 outerHTML 的区别?
innerHTML 和 outerHTML 是操作 DOM 的两个常用属性,
innerHTML表示一个元素的 内部 HTML 内容。
outerHTML 表示一个元素 自身及其内部 HTML 内容。
<div id="example">Hello, <b>world</b>!</div>
<script>
const div = document.getElementById("example");
console.log(div.innerHTML); // 输出: Hello, <b>world</b>!
div.innerHTML = "New Content";
console.log(div.outerHTML); // 输出: <div id="example">New Content</div>
</script>
7,如何编写高性能的 Javascript ?
1.使用位运算代替一些简单的四则运算。 2.避免使用过深的嵌套循环。 3.不要使用未定义的变量。 4.当需要多次访问数组长度时,可以用变量保存起来,避免每次都会去进行属性查找。
8.call() 和 .apply() 的区别?
它们的作用一模一样,区别仅在于传入参数的形式的不同。
call()
-
参数形式: 参数逐个传递。
-
语法:
func.call(thisArg, arg1, arg2, ...) -
用法场景: 适用于参数数量明确且已知的情况。
apply()
- 参数形式: 参数以数组或类似数组的形式传递。
- 语法:
func.apply(thisArg, [arg1, arg2, ...]) - 用法场景: 适用于参数来源是数组或不确定参数数量的情况。
9,### JavaScript 类数组对象的定义?
类数组对象(Array-like Object)是一个看起来像数组,但不完全是数组的对象
-
拥有类似数组的结构:
- 通常有数值索引(如
0,1,2)。 - 可能有
length属性,表示对象的元素数量。
- 通常有数值索引(如
-
不是真正的数组:
- 它并没有数组的方法,比如
push、pop或forEach等。
- 它并没有数组的方法,比如
-
常见的类数组对象:
arguments对象:函数中的参数列表。- DOM 方法返回的
NodeList或HTMLCollection。 - 自定义对象,只要满足类数组的特征。
// 一个类数组对象
const arrayLike = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
console.log(arrayLike[0]); // 输出: 'a'
console.log(arrayLike.length); // 输出: 3
转换为真正数组的方法
const realArray = Array.from(arrayLike);
console.log(realArray); // 输出: ['a', 'b', 'c']
const realArray2 = [...arrayLike];
console.log(realArray2); // 输出: ['a', 'b', 'c']
10,数组和对象有哪些原生方法,列举一下?
以下是 JavaScript 中数组和对象的常用原生方法:
数组的原生方法
-
操作元素
push():向数组末尾添加元素。pop():移除数组末尾的元素。unshift():向数组开头添加元素。shift():移除数组开头的元素。splice(start, deleteCount, ...items):在指定位置添加/删除元素。concat():合并多个数组。
-
查找与筛选
indexOf():查找元素第一次出现的索引。lastIndexOf():查找元素最后一次出现的索引。includes():判断数组是否包含某个元素。find(callback):返回第一个满足条件的元素。findIndex(callback):返回第一个满足条件的元素索引。filter(callback):返回满足条件的所有元素组成的新数组。
-
遍历与变换
forEach(callback):遍历数组。map(callback):创建新数组,元素为回调函数的返回值。reduce(callback, initialValue):累加数组中的值。reduceRight(callback, initialValue):从右向左累加值。
-
排序与反转
sort():排序数组(默认按字符串排序,可自定义比较函数)。reverse():反转数组顺序。
-
分割与拼接
slice(start, end):返回数组的子数组。join(separator):将数组元素拼接为字符串。flat(depth):将多维数组扁平化。flatMap(callback):映射并扁平化数组。
-
其他
Array.isArray():判断是否为数组。length:返回数组的长度。
对象的原生方法
-
操作对象
Object.assign(target, ...sources):合并对象。Object.create(proto, propertiesObject):创建新对象,指定原型。Object.defineProperty(obj, prop, descriptor):定义属性。
-
获取对象信息
Object.keys(obj):返回对象所有可枚举属性的键。Object.values(obj):返回对象所有可枚举属性的值。Object.entries(obj):返回对象键值对的数组。Object.getOwnPropertyNames(obj):返回对象自身所有属性的键。Object.getOwnPropertyDescriptor(obj, prop):获取属性的描述符。Object.hasOwn(obj, prop):判断对象是否有某个自身属性。
-
判断与比较
Object.is(value1, value2):判断两个值是否严格相等。Object.hasOwnProperty(prop):判断是否有某个自身属性。Object.prototype.toString():返回对象的字符串表示。
-
对象原型
Object.getPrototypeOf(obj):获取对象原型。Object.setPrototypeOf(obj, proto):设置对象原型。
-
冻结与密封
Object.freeze(obj):冻结对象(不可修改)。Object.isFrozen(obj):判断对象是否被冻结。Object.seal(obj):密封对象(不可添加新属性)。Object.isSealed(obj):判断对象是否被密封。
11,数组和对象有哪些原生方法,列举一下?
用一个固定值填充一个数组中从起始索引到终止索引内的全部元素
没错!以下是对 fill() 方法的详细说明和示例:
语法
array.fill(value, start, end)
value(必需):用来填充数组的值。start(可选):开始填充的位置,默认值为0。end(可选):停止填充的位置(不包括该索引),默认值为array.length。
特性
- 会直接修改原数组,并返回修改后的数组。
start和end支持负值:- 负值会从数组末尾开始计算索引,例如
-1表示最后一个元素。
- 负值会从数组末尾开始计算索引,例如
示例
- 基本用法:
const arr = [1, 2, 3, 4, 5];
console.log(arr.fill(0)); // 输出: [0, 0, 0, 0, 0]
- 指定
start和end:
const arr = [1, 2, 3, 4, 5];
console.log(arr.fill(9, 1, 4)); // 输出: [1, 9, 9, 9, 5]
// 从索引 1 填充到索引 4(不包含 4)
- 使用负索引:
const arr = [1, 2, 3, 4, 5];
console.log(arr.fill(7, -3, -1)); // 输出: [1, 2, 7, 7, 5]
// 等效于 fill(7, 2, 4)
- 填充空数组:
const arr = new Array(5);
console.log(arr.fill(1)); // 输出: [1, 1, 1, 1, 1]
注意点
fill()方法直接改变原数组,而不是返回新数组。- 如果数组是稀疏数组,
fill()会对每个索引赋值,变成密集数组。
12, [,,,] 的长度?
原因
在 JavaScript 中,数组最后的逗号是可忽略的。因此:
const arr = [,,,];
实际上等价于:
const arr = [undefined, undefined, undefined];
但如果写成 [...,],它等价于:
const arr = [undefined];
示例验证
console.log([,,,].length); // 输出: 3
console.log([...].length); // 输出: 1
console.log([...,,].length); // 输出: 1
总结:多余的逗号只影响数组的视觉呈现,不会增加数组的长度。
13 ECMAScript6 怎么写 class,为什么会出现 class 这种东西?
引入了 class 语法,提供了更清晰、更接近面向对象语言的方式来定义类。
14如何判断一个对象是否属于某个类?
15 Ajax 是什么? 如何创建一个 Ajax?
我对 ajax 的理解是,它是一种异步通信的方法,通过直接由 js 脚本向服务器发起 http 通信,然后根据服务器返回的数据,更新网页的相应部分,而不用刷新整个页面的一种方法。
// 创建 XMLHttpRequest 对象
const xhr = new XMLHttpRequest();
// 配置请求方式和 URL
xhr.open('GET', 'https://api.example.com/data', true); // true 表示异步
// 监听响应
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) { // 请求成功
console.log(xhr.responseText); // 输出响应数据
}
};
// 发送请求
xhr.send();
16,谈一谈浏览器的缓存机制?
浏览器的缓存机制
浏览器的缓存机制是为了提升网页加载速度、减少网络请求和服务器压力的一种技术。它通过将已访问的资源(如 HTML、CSS、JS、图片等)存储在本地,避免重复请求,提高用户体验。
缓存的分类
-
强缓存:
- 不向服务器发送请求,直接使用本地缓存。
- 通过 HTTP 响应头控制,如
Expires和Cache-Control。 - 特点:
- 命中强缓存时,返回状态码为 200(from disk cache 或 memory cache)。
-
协商缓存:
- 浏览器向服务器发送请求,服务器根据资源是否修改决定是否使用缓存。
- 通过 HTTP 响应头
Last-Modified/If-Modified-Since或ETag/If-None-Match实现。 - 特点:
- 如果资源未修改,返回状态码 304(Not Modified),浏览器继续使用本地缓存。
缓存的 HTTP 头
1. 强缓存控制
-
Expires(HTTP/1.0):指定资源过期时间(绝对时间,受客户端时间影响)。Expires: Fri, 20 Nov 2024 10:00:00 GMT -
Cache-Control(HTTP/1.1):更灵活的缓存控制(优先级高于Expires)。- 常见指令:
max-age=3600:缓存的有效时间(秒)。no-cache:需要协商缓存验证。no-store:不使用缓存,每次都请求服务器。public:资源可以被客户端和代理服务器缓存。private:资源仅能被客户端缓存。
- 常见指令:
2. 协商缓存控制
-
Last-Modified和If-Modified-Since:Last-Modified:资源最后一次修改的时间。If-Modified-Since:浏览器发送的头,表示上次的修改时间。
Last-Modified: Fri, 20 Nov 2024 09:00:00 GMT- 缺点:
- 修改时间不够精确(只能精确到秒)。
- 文件内容未变,但修改时间更新,导致缓存失效。
-
ETag和If-None-Match:ETag:资源的唯一标识符(通常是文件的哈希值)。If-None-Match:浏览器发送的头,用于校验ETag是否匹配。
ETag: "5d8c72a5edda5-18a"
缓存的流程
-
浏览器请求资源,首先检查本地缓存:
- 如果命中 强缓存,直接使用本地资源,不发请求。
- 如果未命中强缓存,发送请求到服务器。
-
服务器收到请求:
- 根据 协商缓存 验证资源是否修改。
- 如果未修改,返回
304,浏览器使用本地缓存。 - 如果已修改,返回新的资源和状态码
200。
缓存的优先级
强缓存 > 协商缓存 > 不缓存。
常见场景和优化策略
-
静态资源缓存:
- 对静态资源(如图片、CSS、JS)使用长时间强缓存(
Cache-Control: max-age=31536000)。 - 通过文件名哈希值实现版本控制(如
style.abc123.css)。
- 对静态资源(如图片、CSS、JS)使用长时间强缓存(
-
动态资源缓存:
- 动态数据使用短时间缓存或禁用缓存(
Cache-Control: no-store)。
- 动态数据使用短时间缓存或禁用缓存(
-
清理缓存:
- 为了解决缓存更新问题,可以结合
ETag或修改资源 URL(如增加时间戳或版本号)。
- 为了解决缓存更新问题,可以结合
总结
浏览器缓存机制通过 强缓存 和 协商缓存 来减少不必要的网络请求,提升性能。开发中应合理利用缓存头来提高页面加载速度,同时确保资源的实时性和正确性。