下面这个例子可以获取到最新的值吗?
2026/7/23 13:05:35 网站建设 项目流程
更改时间 获取时间 现在问大家获取的值是: {startTime: 0, endTime: 0} 还是 {startTime: 1000, endTime: 10} ? 也许很多小伙伴都认为获取的值是: {startTime: 1000, endTime: 10} 实际上不是,获取的是:{startTime: 0, endTime: 0} image

分析原因
当 timeChange 函数中执行 timeObject = { startTime, endTime } 时,
修改的是对象引用(因为重新赋值了整个对象)
此时 timeObject 指向了一个新的对象。
但是返回的对象中的 timeObject 仍然指向原来的对象
因此外界获取不到最新的值。只能够拿到初始值(原来那个对象的值)。

或者说:修改对象的属性(object.xx =)改的是房子里的东西;
重新赋值(=)换的是房子本身,
外部拿的旧钥匙打不开新房子

在JavaScript中,对象是通过引用传递的
核心是:在JavaScript中,对象是通过引用传递的,当重新赋值整个(对象)变量时,
它指向了一个新的对象,而外部持有的(旧引用)不会自动更新。

解决办法一:逐一修改对象的属性
function leftTimeRelatedFun() {
// 此时页面上显示的开始时间和结束时间
let timeObject = {
startTime:0,
endTime:0
}
// 选择了时间按钮
function timeChange() {
console.log(‘更改了时间’)
const endTime = 1000
const startTime = 10
//第1种:修改:timeObject 变量本身没有变,
// 只是修改了对象内部的属性值。对象的引用没有发生变化;始终指向同一个对象。外部持有的引用能看到最新的变化。
timeObject.startTime = startTime; timeObject.endTime = endTime
}
return {
timeObject,
timeChange
}
}
const {
timeObject,
timeChange
} = leftTimeRelatedFun()
解决办法二:返回一个 getter 函数
function leftTimeRelatedFun() {
let timeObject = { startTime: 0, endTime: 0 }

function timeChange() {
timeObject = { startTime: 10, endTime: 1000 }
}

// 通过这个方法来获取;闭包总是拿到最新的引用,
function getTimeObject() {
return timeObject
}

return { getTimeObject, timeChange }
}

const { getTimeObject, timeChange } = leftTimeRelatedFun()

function lookForTime() {
console.log(‘最新值’, getTimeObject())
}
image

我们在看下这个题
function change(obj) {
obj.name = ‘changed’;
obj = { name: ‘new’ };
obj.name = ‘inner’;
}
let data = { name: ‘outer’ };
change(data);
console.log(data.name); // 输出的是什么?
正确答案:输出的是changed

分析
当你把 data 传入 change 函数时
函数内部的形参 obj 和外面的 data 指向同一个对象(地址 0x001)。
此时内存情况:
data (地址 0x001) → { name: ‘outer’ }
obj (地址 0x001) → { name: ‘outer’ }
函数内部执行obj.name = ‘changed’;
它修改的是对象中的属性,引用地址没有发生改变。
此时的内存情况:
data (地址 0x001) → { name: ‘changed’ }
obj (地址 0x001) → { name: ‘changed’ }

obj = { name: ‘new’ };执行第二行代码(关键转折点)
这里不是修改原来的对象,而是给 obj 变量重新赋值了一个新的对象(新地址 0x002)
此时内存情况:
data (地址 0x001) → { name: ‘changed’ } (还在指着老对象)
obj (地址 0x002) → { name: ‘new’ } (换指了新对象)
然后执行obj.name = ‘inner’;

修改的是新对象(地址 0x002),老对象(地址 0x001)纹丝不动
函数执行完毕,打印 data.name 输出的是changed

总结函数传参:
如果传递的是引用类型,函数内部属性的修改会影响外部的变量。
如果重新赋值整个对象,则函数内部的参数和外部的变量引用地址发生了变化,以后他们之间修改互不影响

下面的题
function test(person) {
// 传递的是引用类型,函数内部属性的修改会影响外部的变量
person.age = 25;
// 传递的是引用类型,重新赋值整个对象,函数内部的参数和外部的变量引用地址发生了变化,以后他们之间修改互不影响
person = { age: 30 };
person.age = 35;
return person;
}

const p1 = { age: 20 };
// 此时 p2 = { age: 35}
const p2 = test(p1);

console.log(p1.age); // 输出25
console.log(p2.age); // 输出35
下面这个题
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs.push(function() { console.log(i); });
}
funcs0; // 3
funcs1; // 3
funcs2; // 3
核心原因有两个:

var 没有块级作用域
循环过程中,i 一直在被修改,最终停在了 3
2.闭包捕获的是变量引用,不是值
当函数真正执行时(你调用 funcs0 时),循环早已结束,i 已经是 3 了。
怎么改成输出 0、1、2?
var funcs = [];
for (let i = 0; i < 3; i++) { // let 有块级作用域
funcs.push(function() { console.log(i); });
}
funcs0; // 0
funcs1; // 1
funcs2; // 2
请问依次点击三个按钮控制台分别输出什么?
0
1
2

输出的是3。原因是当点击按钮的时候,循环已经结束了。
此时的i=3;所以输出的是3

obj2 = obj1 会让 obj2 和 obj1 指向同一个对象
let obj1 = { name: ‘Alice’ };
let obj2 = obj1; // { name: ‘Alice’ }
obj2.name = ‘Bob’; // { name: ‘Bob’ }
console.log(obj1, obj2) // { name: ‘Bob’ }
总结 obj2 = obj1 会让 obj2 和 obj1 指向同一个对象,他们的引用地址是相同的

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询