JavaScript 作为前端开发的基石,其核心特性决定了代码的运行机制与行为逻辑。本文将从严格模式、this 指向、变量提升、函数声明等核心概念入手,结合实战代码案例,逐点拆解细节,帮助你构建清晰的知识体系。
一、严格模式:让 JS 更 “守规矩” 💻
严格模式("use strict")是 ES5 引入的一种代码约束机制,通过消除语言的不合理特性、增强安全性,让代码更严谨。
1.1 严格模式的启用方式
- 全局启用:在脚本顶部添加
"use strict";。 - 局部启用:在函数内部顶部添加,仅约束当前函数(避免污染全局)。
// 全局严格模式
"use strict";
var b = 10;
(function b(){
b = 20; // 不生效(函数名只读)
console.log(b); // 输出函数本身:f b() {...}
})()
1.2 严格模式的核心作用
-
消除不合理行为
- 禁止隐式全局变量(未声明的变量赋值会报错,非严格模式下会自动挂到顶层对象)。
- 禁止删除变量 / 函数(
delete b会报错,非严格模式下无效但不报错)。
-
增强安全性
- 禁止函数内部修改函数名(函数名在函数体内是只读局部变量,如上面中的
b=20不生效)。 - 严格模式下,普通函数调用时
this指向undefined(非严格模式指向window,见下文this部分)。
- 禁止函数内部修改函数名(函数名在函数体内是只读局部变量,如上面中的
-
提升性能与兼容性
- 编译器可优化代码(减少动态类型判断),提升运行速度。
- 禁止未来版本可能移除的语法(如
with语句),为升级铺路。
1.3 实战易错点
- 函数名只读特性:在严格模式下,函数体内的函数名是 “常量”,赋值会报错
Assignment to constant variable。 - 全局变量与顶层对象分离:严格模式下,
var声明的全局变量不再自动挂到window(非严格模式会挂载)。
二、this 指向:谁调用,指向谁 🎯
this 是函数执行时自动生成的 “调用者指针”,其指向完全由调用方式决定,与声明位置无关。
2.1 普通函数调用(非对象方法)
- 非严格模式:
this指向顶层对象(浏览器为window,Node 为global)。 - 严格模式:
this指向undefined。
<!-- 非严格模式 -->
<script>
var name = '小王';
function func(){
console.log(this); // window
console.log(this.name); // 小王
}
func(); // 等价于 window.func(),this 指向 window
</script>
2.2 对象方法调用
函数作为对象的属性被调用时,this 指向当前对象(调用者)。
<script>
"use strict"
var name = "windowsName";
var a = {
name:'小娄',
fn:function(){
console.log(this); // {name: '小娄', fn: ƒ}
console.log(this.name); // 小娄
}
}
a.fn(); // 调用者是 a,this 指向 a
</script>
注意:若方法被赋值给变量后调用,this 会丢失原对象指向:
var b = a.fn;
b(); // 此时是普通函数调用,严格模式下 this 为 undefined(非严格模式指向 window)
2.3 构造函数调用(new 关键字)
用 new 调用函数时,this 指向新创建的实例对象。
<script>
function Person(name,age){
this.name = name; // this 指向新实例 p
this.age = age;
}
const p = new Person('labubu',2);
console.log(p.name); // labubu(实例属性被正确赋值)
</script>
2.4 事件处理函数
DOM 事件回调中,this 指向触发事件的元素。
<input type="text" id="inp"/>
<script>
document.getElementById('inp').addEventListener('keydown',function(){
console.log(this); // <input type="text" id="inp"/>(当前输入框元素)
console.log(this.value); // 输入框中的值
})
</script>
2.5 箭头函数:没有自己的 this ⚠️
箭头函数不绑定 this,其 this 继承自外层作用域的 this(静态绑定,声明时确定)。
<script>
var name = "windowsName";
var a = {
name:'Tom',
func1:function(){
console.log(this.name); // Tom(this 指向 a)
},
fun2:function(){
// 外层作用域 this 指向 a
setTimeout(() => {
this.func1(); // 正确调用(this 继承自 fun2 的 this)
},1000)
// 若用普通函数:this 指向 window,会报错
// setTimeout(function(){ this.func1() },1000) // 报错
}
}
a.fun2(); // 1秒后输出 Tom
</script>
三、变量提升:JS 引擎的 “预编译” 机制 🔄
变量提升是 JS 引擎在编译阶段的特性:var 声明的变量和函数声明会被 “提前” 到作用域顶部,但赋值留在原地。
3.1 变量提升的底层逻辑(文档 2+3)
-
编译阶段:引擎扫描代码,将
var a提升到当前作用域顶部(仅声明,不赋值)。 -
执行阶段:从顶部开始执行,赋值操作在原位置执行。
// 示例:变量提升
console.log(a); // undefined(声明被提升,赋值未执行)
var a = 1;
console.log(a); // 1(赋值执行后)
3.2 函数声明 vs 变量声明:函数优先级更高
函数声明会被完整提升(包括函数体),且优先级高于变量声明。
// 隐含逻辑
var b = 10; // 变量声明(提升后被函数声明覆盖)
(function b(){ // 函数声明(完整提升,优先级更高)
console.log(b); // 输出函数本身,而非外部变量 10
})()
3.3 全局变量与顶层对象
-
浏览器环境:非严格模式下,
var声明的全局变量会挂到window上(let/const不会)。<script> var a = 1; console.log(window.a); // 1(var 全局变量 → window 属性) let b = 2; console.log(window.b); // undefined(let 全局变量在 Script 块作用域) </script> -
Node 环境:顶层对象是
global,var全局变量挂到global上。// Node 环境 var a = 1; console.log(global.a); // 1
四、函数声明:函数名的 “只读” 特性 📜
函数声明在函数体内是只读局部变量,无法被重新赋值(严格模式下会报错)。
4.1 实战案例
"use strict";
var b = 10;
(function b(){
b = 20; // 严格模式下报错:Assignment to constant variable
console.log(b); // 若非严格模式,输出函数本身(赋值无效)
})()
- 原因:函数名在函数体内被视为 “只读常量”,即使 JS 是弱类型语言,也不允许修改。
总结:核心知识点梳理 📝
| 特性 | 核心要点 |
|---|---|
| 严格模式 | 约束语法、禁止不合理行为、this 指向 undefined(普通函数)、函数名只读 |
this 指向 | 普通调用→window/undefined、对象方法→对象、new→实例、箭头函数→继承外层 |
| 变量提升 | var 和函数声明被提升,函数优先级高于变量,let/const 无提升(有 TDZ) |
| 函数声明 | 函数名在体内只读,严格模式下赋值报错 |
掌握这些特性,能帮你避开 80% 的 JS 坑!如果有疑问,欢迎在评论区交流讨论哦 😊~