(五)前端,如此简单!---变量

js中有三种方式可以声明变量:varletconst

可以从以下方面来区分他们。

一、作用域

  • 在函数外

    var globalVar = "我是全局变量"; // var会声明全局变量
    let letVar = "我不是window属性"; // let声明的不会声明全局变量
    const constVar = "我也不是"; // const声明的也不会

    // 全局变量自动成为window的属性
    console.log(window.globalVar); // "我是全局变量"
    console.log(window.letVar); // undefined
    console.log(window.constVar); // undefined

  • 在函数内

    function test() {
    if (true) {
    var x = 10; // 函数作用域
    let y = 20;
    const z = 30; // let/const - 块级作用域
    }
    console.log(x); // 10 - 在函数内可访问
    console.log(y); // ReferenceError: y is not defined
    console.log(z); // ReferenceError: z is not defined
    }

二、变量提升

变量提升就是JavaScript 在编译阶段就把所有变量声明记录进作用域,但赋值操作仍留在原地的一种机制。

声明"提前",赋值"不动"。

复制代码
// var a = 5;提到了前面
console.log(a); // undefined (不会报错)
var a = 5;

// let/const  编译时已知道有个变量 b,但进入 TDZ(暂时性死区),
// 在 let/const b 语句执行完之前都不能读/写。
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;

三、重新赋值

varlet 可以重新赋值,const 不可以重新赋值,但可以改属性

复制代码
var name = "Alice";
name = "Bob"; // ✅

let age = 25;
age = 26; // ✅

const PI = 3.14; //const 变量必须在声明时赋值
PI = 3.14159; // TypeError: Assignment to constant variable

const person = { name: "Alice" };
person = { name: "Bob" }; // ❌ 不能重新赋值
person.name = "Bob"; // ✅ 可以修改属性

const numbers = [1, 2, 3];
numbers = [5, 6, 7]; // ❌ 不能重新赋值
numbers.push(4); // ✅ 可以修改数组内容

// 冻结对象(浅冻结)
const obj = { name: 'Alice', info: { age: 18 } };
Object.freeze(obj);     // 第一层冻结
obj.name = 'Bob';       // 静默失败(严格模式会抛错)
obj.info.age = 20;      // ✅  freeze 只冻结浅层

四、重复声明

var可以重复声明,letconst不能

复制代码
var count = 1;
var count = 2; // ✅ 不会报错

let total = 10;
let total = 20; // ❌ SyntaxError: Identifier 'total' has already been declared

const MAX = 100;
const MAX = 200; // ❌ SyntaxError: Identifier 'MAX' has already been declared

var count = 1;
var count = 2;
console.log(count);
// 同一块作用域里多次 var 声明会被合并。等价于============ >>
var count;   // 提升后只声明一次
count = 1;   // 第一次赋值
count = 2;   // 第二次赋值
console.log(count); // 2

五、总结

  • 如果值不需要改变 用 const

    const API_URL = "https://api.example.com";
    const container = document.getElementById('container');

  • 需要重新赋值时使用 let

    let counter = 0;
    counter = 1; // 需要改变值

    for (let i = 0; i < 10; i++) {
    // 循环变量需要改变
    }

  • 容易引起错误的 var

    for (var i = 0; i < 5; i++) {
    console.log(i); // 输出 0、1、2、3、4。同步执行
    }

    for (var i = 0; i < 5; i++) { // var 是函数作用域,所有回调都引用同一个 i
    setTimeout(function() { // 循环会立即执行完毕,i 的值从 0 增加到 5
    console.log(i); // setTimeout 的回调是异步的,会在 100ms 后执行
    }, 100); // 当回调函数执行时,循环早已结束,此时的 i 已经是 5
    } // 所以输出 5个5。

    for (let i = 0; i < 5; i++) { // let 是块作用域,每次循环迭代都会创建一个新的 i 变量
    setTimeout(function() { // 这就形成了 5 个独立的闭包
    console.log(i); // 输出 0、1、2、3、4
    }, 100);
    }

    // var 通过立即执行函数来创建闭包,实现同样的效果
    for (var i=0; i<5; i++){
    function(j){ // t=0ms: 循环开始,创建5个定时器
    setTimeout(function(){ // t=0ms: 循环结束
    console.log(j); // t=100ms: 5个定时器同时触发,打印 0 1 2 3 4
    }, 100);
    }(i)
    }

六、跨js文件的变量

index.html 中有一个按钮

复制代码
<button onclick="dayin()">点击</button>

<!-- type="module" 是使用 import 的关键 -->
<script type="module" src="script.js"></script>

script.js 从 test.js 导入变量

复制代码
import { url } from './test.js'

// type="module",这个函数默认不会添加到全局 window 对象
// 需要通过 window.dayin = dayin 显式暴露给全局作用域
window.dayin = dayin;

function dayin() {
	alert(url);
}

test.js中的变量需要导出

复制代码
// export 导出 url 变量,使其他模块可以导入使用
export var url = "yang";
相关推荐
wsdswzj17 分钟前
web与web服务器基础安全
服务器·前端·安全
JarvanMo17 分钟前
Flutist - Flutter 模块化架构管理框架
前端
GISer_Jing20 分钟前
AI Agent Skills 发现指南:前端工程化与自动化全景
前端·人工智能·自动化
心.c20 分钟前
从 Function Call 到渐进式 Skill:大模型能力扩展范式的演进与落地实践
前端·人工智能·react.js·ai·react
IT_陈寒21 分钟前
Vue的响应式更新把我坑惨了,原来问题出在这里
前端·人工智能·后端
Cobyte25 分钟前
6.响应式系统比对:通过 Vue3 响应式库写 React 应用
前端·javascript·vue.js
Alice-YUE29 分钟前
【前端面试之ai概念】大白话讲清 Agent、MCP、Skill、Function Calling、RAG
前端·人工智能·学习·aegnt
苏武难飞43 分钟前
THREE.JS实现一个魔法镜子!
前端·css·three.js
云浪1 小时前
从 0 到 1 搭建 RAG 应用:用 LangChain + Chroma + qwen-plus 实现《红楼梦》问答
javascript·vue.js·人工智能
小流苏生1 小时前
工作十年了,慢慢学习敬畏死亡
前端·程序员·ai编程