# 说说 JS 预编译/处理
JS 是 解释性 语言,就是从上到下从左到右逐行解析,逐行执行。
预编译:JS 在真正被解析之前,JS 引擎先把整个文件进行预处理并消除一些歧义的过程。
全局 / 局部 预编译过程大致如下:
- 产生全局对象
window。 - 查找所有变量,并把查找到的变量作为
window的属性,值为undefined - 查找所有函数,并把查找到的函数作为
window的属性,值为function - 全局预编译结束,代码从上到下从左到右依次执行。
当执行到调用函数时,开始了局部预编译:
- 代用函数时,产生了函数的活动对象
AO。 - 查找函数内部变量并作为
AO的属性,值为undefined。 - 这时函数如果有传参的话,把传过来的参数赋值给形参。
- 查找函数内部函数并作为
AO的属性,值为function。 - 局部预编译结束,开始从上到下从左到右依次执行代码。
有的地方说,函数优先级比变量高,所以在变量提升和函数提升时,变量会被同名函数覆盖,其实原理还是预处理的过程是先变量后函数。
优先级为:函数 > 实参 >局部变量
# 说说全局对象/变量/函数
全局对象(Global Object):
在浏览器环境中,JS 引擎会整合所有 <script>标签的内容,产生 window 这个全局对象。
在 node 环境中会产生 global 对象
在所有 <script> 标签里内容执行完后销毁
全局变量:
在 <script> 标签中声明的 变量,会作为 window的属性 存在
全局函数:
在 <script> 标签中声明的 函数,会作为 window的方法 存在
# 说说活动对象/局部变量/函数
活动/激活对象(Activation Object):
在函数调用时产生,用来保存当前函数内部的执行环境,也叫 执行期上下文。
在函数调用结束时销毁
局部变量:
在函数内部声明的 变量,作为 AO 对象的 属性 存在
局部函数:
在函数内部声明的 函数,作为 AO 对象的 方法 存在
# 给出下面的思路和答案
let a = ?
if(a==1&&a==2&&a==3){
console.log('123');
}
描述:a 等于什么值时,可以使表达式成立
其实这道题想考察的,就是我们对 取值 的理解 和 隐式转换的理解。
比如 [10] == 10 ==> true
其实是 [10] 隐式转换了字符串即 Number([10].toString()) == 10
这里 == 比较值时有这么几个规律:
-
对象 == 字符串时对象.toString()转换为字符串 -
null和undefined相等,和其他值不相等 -
NaN和任何值都不相等包括自己 - 其余的都转换为
数字
解题思路大致分为两大类:toString 和 defineProperty
法一:toString 重写
let a = {
i: 0,
toString(){
return ++this.i;
}
}
if(a==1 && a==2 && a==3){
console.log('条件成立');
}
或者
var a = [1,2,3];
a.toString = a.shift;
if(a==1 && a==2 && a==3){
console.log('条件成立');
}
法二:defineProperty 数据劫持
var i = 0;
Object.defineProperty(window,'a',{
get(){
return ++i;
}
})
if(a==1 && a==2 && a==3){
console.log('条件成立');
}
# 一个青蛙一次可跳一个或者两个台阶,求 n 个台阶有多少种跳法
实际上就是斐波那契数列,递归实现
function JumpFloor( n){
if(n<=0){
return -1;
}
if(n==1 || n==2){
return n;
}
else{
return cal(n-1)+cal(n-2);
}
}
# 说说 var let const
- ·var· 声明的变量有声明提前
可以声明不赋值
可以声明相同的变量名,后边会覆盖前面的 -
let声明的变量没有声明提前
可以声明不赋值
同一个作用域下不能重复定义同一个名称,会报错
有严格的函数和块级作用域 -
const声明的变量没有声明提前
不可以声明不赋值,会报错
声明的常量是只读的,不可以修改
声明的对象和数组,可修改其元素,但引用地址不可修改
# 实现一个页面滚动,图片懒加载的js库(快速滑动/滚动,img经过可视区时,不加载图片)
# 实现小球落地的过程
image.png










网友评论