mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-26 11:41:13 +08:00
fix: 顶层 var 全局属性求值前创建(声明定时语义)+ 无初始化 var 声明不再抹槽值
This commit is contained in:
@@ -80,6 +80,17 @@ fn script_top_level_var_still_configurable_false() {
|
||||
assert!(r.is_bool() && r.as_bool(), "脚本顶层 var 应保持 configurable:false,实际 {:?}", r);
|
||||
}
|
||||
|
||||
// ── eval 路径定时:属性在 eval 体求值开始前创建(configurable:true 描述符) ──
|
||||
#[test]
|
||||
fn eval_var_property_created_before_eval_body_runs() {
|
||||
let r = eval("eval(\"var d = (function(){ var p = Object.getOwnPropertyDescriptor(globalThis, 'x'); return p !== undefined && p.configurable === true; })(); var x; d\")").unwrap();
|
||||
assert!(
|
||||
r.is_bool() && r.as_bool(),
|
||||
"eval 体内声明语句前全局属性应已存在且 configurable:true,实际 {:?}",
|
||||
r
|
||||
);
|
||||
}
|
||||
|
||||
// ── 严格 eval:未声明写抛 ReferenceError(Step 2 语义经 eval 路径) ──
|
||||
#[test]
|
||||
fn strict_eval_undeclared_write_throws_reference_error() {
|
||||
|
||||
@@ -98,3 +98,47 @@ fn descriptor_attributes_match_spec() {
|
||||
let d = eval_string("var x = 1; JSON.stringify(Object.getOwnPropertyDescriptor(globalThis, 'x'))");
|
||||
assert_eq!(d, r#"{"value":1,"writable":true,"enumerable":true,"configurable":false}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn var_property_exists_before_declaration_statement() {
|
||||
// 全局声明实例化:属性在脚本求值开始即创建,声明语句执行前的
|
||||
// 反射/读取即可见绑定(值 undefined、脚本模式 configurable:false)。
|
||||
// 断言值经临时全局承载——尾部 var 声明语句会覆盖程序完成值。
|
||||
eval_truthy(
|
||||
"(function(){ seen = Object.prototype.hasOwnProperty.call(globalThis, 'gv'); })(); var gv; seen === true",
|
||||
);
|
||||
eval_truthy("(function(){ seen = (typeof gv === 'undefined'); })(); var gv; seen === true");
|
||||
eval_truthy("(function(){ var p = Object.getOwnPropertyDescriptor(globalThis, 'gv'); seen = (p.configurable === false && p.value === undefined); })(); var gv; seen === true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn var_no_init_preserves_prior_write() {
|
||||
eval_truthy("x = 1; var x; globalThis.x === 1");
|
||||
eval_truthy("x = 1; var x; x === 1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn var_no_init_preserves_prior_write_captured() {
|
||||
// 被捕获 var 的值在 cell:声明语句从 cell 同步全局属性,不抹掉先前写入。
|
||||
eval_truthy("x = 1; var x; (function(){ return x; })() === 1");
|
||||
eval_truthy("x = 1; var x; globalThis.x === 1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn var_self_reference_reads_binding_value() {
|
||||
eval_truthy("var x = x; typeof x === 'undefined'");
|
||||
eval_truthy("x = 7; var x = x; x === 7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_callable_before_its_declaration() {
|
||||
eval_truthy("(function(){ return f() === 42; })(); function f(){ return 42; }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn var_no_init_does_not_clobber_function_binding() {
|
||||
eval_truthy("function f(){ return 1; } var f; typeof f === 'function' && f() === 1");
|
||||
// 不比较 globalThis.f === f 同一性:属性读路径存在预存 codegen 缺陷,
|
||||
// 行为契约是声明后属性仍为原函数对象(可调用、返回值正确)。
|
||||
eval_truthy("function f(){ return 1; } var f; typeof globalThis.f === 'function' && globalThis.f() === 1");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user