我正在創建一種可以編譯到 Swift、Rust 和 JavaScript 的語言(或者至少在嘗試)。Rust 和 Swift 都使用指標/參考/解參考/等,而 JavaScript 沒有。所以在類似 Rust 的語言中,你可能會做這樣的事情:
fn update(x) {
*x
}
fn main() {
let i = 0
update(&i)
log(i) #=> 1
}
在類似 JavaScript 的語言中,如果你這樣做了,它就會失敗:
function update(x) {
x
}
function main() {
let i = 0
update(i)
log(i) #=> 0
}
因為值在傳入時被克隆(我們顯然知道)。
所以我首先想到的是這樣做:
function update(scopeWithI) {
scopeWithI.i
}
function main() {
let i = 0
let scopeWithI = { i }
update(scopeWithI)
i = scopeWithI.i
log(i) #=> 1
}
但這是很多額外的處理,而且似乎是不必要的。相反,我可能會嘗試編譯為:
function update(scopeWithI) {
scopeWithI.i
}
function main() {
let scope = {}
scope.i = 0
update(scope)
log(scope.i) #=> 1
}
這意味著您創建的每個嵌套范圍都必須開始手動創建/管理范圍鏈。實際上這行不通,因為update它被硬編碼為i. 所以你可能必須傳入你想要的變數名。
function update(scope, ...names) {
scope[names[0]]
}
但它就像:
function update(scope, ...names) {
scope[names[0]]
}
function main() {
let scope = {}
scope.i = 0
if random() > 0.5
let childScope = { scope }
childScope.x = 0
update(childScope, ['i'])
update(childScope, ['x'])
update(childScope, ['x'])
log(childScope.x) #=> 2
else
update(childScope, ['i'])
log(scope.i) #=> 1
}
So that seems like it might get us somewhere.
So then it's like, the generic solution is to have scope be the first parameter to a function.
function add(scope, name1, name2) {
return scope[name1] scope[name2]
}
Dereferencing means reading a value directly from the scope, while passing a reference (like &name in Rust or C), would mean passing the scope and the name.
Will something like this work? Or better put, what needs to be changed or added? Does it need to get any more complicated than this?
I would like to try and find a way to transform the pointer-oriented code into JavaScript (transpilation), without at first trying to figure out the seemingly much more complicated approach of not being so direct, and avoiding pointer simulation in JavaScript by redefining a lot of the methods. It seems that avoiding any pointer use in JavaScript would be way harder to figure out, so I am trying to see if a pointer sort of system would be possible to simulate in JavaScript.
To avoid pointer simulation, you would have to redefine methods.
update(x) {
*x
}
Would have to change the outer usage of the function everywhere. So this:
main() {
let i = 0
update(&i)
}
Would become:
main() {
let i = 0
i // inline the thing
}
For this simple case it's fine, but for a more complicated function it starts to seem like macros and might get complicated.
So instead of changing the outer usage, we make it so you have to pass the scope.
Another approach might be to have every variable be an object with a value, so it's more like:
update(x) {
x.value
}
main() {
let i = { value: 0 }
update(i)
}
So then I'm thinking to myself, how to handle references to references then?
update2(x) {
update(&x)
}
update(x) {
*x
}
main() {
let i = 0
update2(&i)
}
In the system i described, that would be like:
update2(x) {
// then what?
let y = { value: x }
update(y)
}
update(x) {
// like this?
x.value.value
}
main() {
let i = { value: 0 }
update2(i)
}
So it seems this wouldn't really work.
uj5u.com熱心網友回復:
不用說,JavaScript 沒有通過參考傳遞引數的通用機制。
圍繞“參考”一詞可能會有些混淆,因為在 JavaScript 中可以將物件傳遞給函式——它們是參考——但這是一種按值呼叫的機制。參考呼叫實際上意味著引數變數是呼叫者變數的別名,因此分配給該別名等同于分配給呼叫者變數。除了一些非常特殊的情況(比如非嚴格模式下的arguments外來物件export,或者機制,或者var與物件的鏈接window,這些都不能以最佳實踐方式幫助你),沒有這樣的變數別名JavaScript 中的機制。
這是一個關于如何var在非嚴格模式下在瀏覽器背景關系中“利用”效果的示例:
function modify(ref) {
// Using the fact that global `var` variables are aliases
// for properties on the global object
// (This is not considered good practice)
globalThis[ref] = globalThis[ref] 1;
}
var a = 1;
modify("a"); // We pass a reference to `a`
console.log(a);
簡而言之,除了舊 JavaScript 語言中的一些糟糕設計(草率模式)之外,這在一般 JavaScript 中是不可能的。您所有有效的嘗試都是通過設定其屬性之一對給定物件執行突變。您不能希望有一個分配給引數變數的函式,從而修改呼叫者的變數。這是不可能的——設計使然。注意assignment和mutation之間的重要區別。
如果呼叫者的變數(不是屬性)需要被賦予一個新值(不僅僅是突變,而是真正的賦值),那么這個賦值必須發生在那個變數上——這是一個函式不能為呼叫者做的事情。
因此,在 JavaScript 中執行這種分配的方法是讓函式回傳呼叫者需要重新分配的任何內容,并且呼叫者仍然有責任執行該分配:
function modify(value) {
return 3;
}
let value = 1;
value = modify(value);
console.log(value);
當涉及多個變數時,讓函式回傳一個“打包”物件,呼叫者可以將其解構為自己的變數:
function modify(a, b) {
return [a 1, b * 2];
}
let a = 1, b = 2;
[a, b] = modify(a, b);
console.log(a, b);
uj5u.com熱心網友回復:
JavaScript 物件是“通過參考”傳遞的:
const obj = {
hello: "world"
};
console.log(obj.hello); // "world"
f(obj);
console.log(obj.hello); // "bob"
function f(s) {
s.hello = "bob";
}
因此,如果您想要像 C、Rust 或 Swift 這樣的“參考”,請將所有內容都放在物件中。考慮
fn update(x) {
x
}
fn main() {
let i = 0
update(&i)
log(i) #=> 1
}
在 JavaScript 中它將是:
function update(obj) {
obj.x
}
const i = { x: 0 };
update(i);
console.log(i.x); // 1
uj5u.com熱心網友回復:
這行得通還是我誤解了?
update2(x) {
update(x)
}
update(x) {
x.value
}
main() {
let i = { value: 0 }
update2(i)
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/434176.html
