ajax
1)ajax请求的原理/ 手写一个ajax请求?
2)readyState?
3)ajax异步与同步的区别?
4)ajax传递中文用什么方法?
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
前言
- 首先引用书籍
你不知道的JavaScript
中的一段话:
回忆我前几年的时光,大量使用JavaScript但却完全不理解闭包是什么。总是感觉言有其隐的一面,如果能够掌握将 会功力大涨,但其讽刺的是我始终无法掌握其中的门道。还记得我曾经大量阅读早期框架的源码,试图能够理解闭包的工作原理,现在还能回忆起我的脑海中第一次浮现出关于 “模块模式” 相关概念时的激动心情。
- 在理解闭包之前,你需要先了解的是执行上下文,当然了你了解V8执行过程就更好了。你可以通过上一篇的文章中学习相关知识,这里详细讲解了V8的执行过程以及执行上下文是如何创建的。
什么是闭包?
- 首先看看维基百科对闭包的定义
闭包
(Closure),又称词法闭包
(Lexical Closure)或函数闭包
(function closures),是在支持头等函数的编程语言中实现词法绑定的一种技术。- 闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。
- 闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行。
- 再来看一下MDN对JavaScript闭包的解释
闭包
(closure)是一个函数以及其捆绑的周边环境状态(lexical environment
,词法环境
)的引用的组合- 闭包能让开发者可以从内部函数访问外部函数的作用域。
- 。在 JavaScript 中,闭包会随着函数的创建而被同时创建。
- 总的来说,闭包就是能够读取其他函数内部变量的函数。
LHS查询和RHS查询
- 在开始闭包之前,我们再来补充一下两个概念,就是什么是## LHS查询和RHS查询,待会要用到。
LSH查询
;LHS查询会在当前作用域链进行查询,如果当前作用域查询不到,就会沿着作用域链一层一层,找到的话就会将值赋值给这个变量,如果到达作用域顶端仍然找不到,就会在作用域链顶端创建这个变量。RHS查询
;RHS查询会在当前作用域链进行查询,如果当前作用域查询不到,就会沿着作用域链一层一层,,找到的话就会取得这个值并返回,如果到达作用域顶端仍然找不到,就会抛出错误(比如TypeError、ReferenceError
)。
闭包的产生
- JavaScript三大特性,而闭包产生的原因也正是因为这些特性:
- 可以在JavaScript函数内部定义新的函数;
- 内部函数中访问函数中的定义;
- 在JavaScript中,函数是一等公民,所以函数中既可以传入一个函数又可以作为参数返回一个函数。
- 话不多说,先上代码:
function foo() {
var moment = 18;
var test = 111;
function bar() {
const may = moment + 777;
return may;
}
console.log(test);
return bar;
}
var baz = foo();
baz(); // 嗨,朋友,这就是闭包
复制代码
- 通过观察上面的代码,我们在foo函数中定义了bar函数,并返回bar函数,同时在bar函数中访问了foo函数中的变量moment。
- 上面的代码大概的执行流程为:
- 当调用
foo
函数时,foo
函数会将它的内部函数bar
返回给全局变量baz
; - 等到
foo
函数执行结束时,执行上下文会被V8
销毁;
- 按照正常的情况来说,变量
moment
已经被 V8 销毁了,因为我们知道 V8 引擎有垃圾回收期用来释放不再使用的内存空间,但是由于存活的函数bar
依然引用了foo
函数作用域中的变量moment
,这样就会带来两个问题:
- 当
foo
执行结束时,变量moment
该不该被销毁?如果不应该被销毁,那么他应该在什么时候销毁,而又应该采用什么策略? - 我们都知道 V8 引擎采用的是惰性解析的方案,那么当执行到
foo
函数时, V8 只会解析foo
函数,并不会解析内部的bar
函数,仅仅知识对bar
函数进行了标记,在这时 V8 引擎并不知道bar
函数中是否引用了 外层函数作用域中的变量moment
;
- 由于
JavaScript
是一门基于堆和栈的语言。在执行全局代码时当执行,V8
会将全局执行上下文压入到调用栈中,然后进入执行foo
函数的调用过程。 - 这时候
V8
引擎会为foo
函数创建执行上下文,执行上下文中包括了变量moment
,然后将foo
函数的执行上下文压入栈中,foo 函数执行结束之后,foo 函数执行上下文从栈中弹出,这时候foo
执行上下文中的变量moment
也随之被销毁。 - 正常的处理方式应该是
foo
函数的执行上下文被销毁了,但是bar
函数引用的foo
函数中的变量却不能被销毁。 - 在执行
foo
函数的阶段,虽然采取了惰性解析,不会解析和执行foo
函数中的的bar
函数中的bar
函数,但是V8
还是需要判断bar
函数是否引用了foo
函数中的变量。 V8
引擎引入了预解析器,当解析顶层代码的时候,遇到了一个函数,那么预解析器并不会直接跳过该函数,而是对该书做一次快速的预解析,其中主要的目的主要有两个:
- 判断当前函数是否是不是存在一些语法上的错误,如果发现语法错误,那么就会向 V8 抛出语法错误;
- 判断
foo
函数是否有被bar
函数引用的变量,如果有,就会把该变量复制一份到堆内存中,同时bar
函数本身也是一个对象,也会被存放到内存当中,这样即使foo
函数即使执行完成,内存被释放以后,bar
函数在执行的时候,依然可以从堆内存中访问复制过来的变量;
- 第二点钟说的复制一个变量,实际上是复制了一个闭包函数(
Closure (foo)
),但是此函数只有被bar
函数引用的值,foo
函数中的test
变量并没有被复制过去,如下图所示:
Other Example
function foo() {
var moment = 777;
function baz() {
console.log(moment);
}
bar(baz);
}
function bar(fn) {
fn(); // 这也是一个闭包
}
foo();
复制代码
- 把内部函数
baz
传递给bar
函数,当调用这个内部函数时(这个时候叫作fn
),它涵盖的foo
()内部作用域的闭包就可以观察到了,因为他能够访问。
function wait(message) {
setTimeout(function timer() {
console.log(message);
}, 1000);
}
wait("hello world");
```js
function wait(message) {
setTimeout(function timer() {
console.log(message);
}, 1000);
}
wait("hello world"); // 这也是一个闭包
复制代码
- 将一个内部函数
timer
传递给settimeout
(…)。timer函数依然保存有wait
(…)作用域的闭包。 - 在引擎内部,内置的工具函数
settimeout
(…)持有对一个参数的引用,这个参数也许叫作fn或者func,又或者其他类型的名字。引擎会调用这个函数,在这个例子中就是内部的timer函数,而词法作用域在这个过程中保持完整。
经典永不过时
for (var i = 0; i <= 5; i++) {
setTimeout(() => {
### 最后
本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是给大家的。知识点涉及比较全面,包括但不限于**前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等**
>**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**
![](https://img-blog.csdnimg.cn/img_convert/5b4cbd4cd8aa333e03cb949349a8d65f.webp?x-oss-process=image/format,png)
**前端视频资料:**
![](https://img-blog.csdnimg.cn/img_convert/59ae3b20b4ddde10d68b1011a48c93dc.webp?x-oss-process=image/format,png)
[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**
[外链图片转存中...(img-DZWJN0Xj-1715393768496)]
**前端视频资料:**
[外链图片转存中...(img-6erRwUQM-1715393768497)]