TypeScript 中的引用是怎么回事?

What's going on with references in TypeScript?

我对 JavaScript 和 TypeScript 还很陌生。

就我而言,TypeScript 被编译成常规 JavaScript。

来自 C#,其中对象通过引用传递(如果它们不是原始类型或结构)。我写了一些 TypeScript 代码来测试一些东西:

interface IRunner { 
    run(): string;
}

class TestDI {
    private readonly Runner: IRunner;

    constructor(runner: IRunner) {
        this.Runner = runner;
    }

    test(): void {
        console.log('Result of runner: ' + this.Runner.run());
    }
}

class FooRunner implements IRunner {
    run(): string {
        return 'Foo';
    }
}

class BarRunner implements IRunner {
    run(): string {
        return 'Bar';
    }
}

let runner: IRunner;
runner = new FooRunner();

const SUT: TestDI = new TestDI(runner);

// Expected output: Foo
// Actual output: Foo
console.log(runner.run());

// Expected output: Foo
// Actual output: Foo
SUT.test();

runner = new BarRunner();

// Expected output: Bar
// Actual output: Bar
console.log(runner.run());

// Expected output: Bar
// Actual output: Foo
SUT.test();

在上面的代码中,我将 IRunner 接口的一个实例传递给了 class c-tor,然后,我的 class 的一个字段填充了我传递的任何内容在 c-tor 中。

稍后在代码中我更改了传递给 c-tor 的变量,但是,当我调用 test 函数时 class 的 Runner 字段似乎没有反映在创建 TestDI class.

的实例时对我传递的原始变量所做的任何更改

在 C# 中,我编写的代码将按照我的预期运行。但这里不是。

怎么回事?

尽量保持简单明了:您传递的是对象 new FooRunner() 的引用,而不是变量 runner 的引用,因此将新值赋给 runner 不会更改您传递给构造函数的内容,并且 SUT.Runner 保持不变。

In C# the code I've written would behave as I expect it to. But here it's not.

不是真的...如果您将上面的代码转换为 C# 代码并 运行 它,您会发现它的行为与您的 TypeScript 代码完全一样。

原因是你把runner传给了TestDI的构造函数。这里发生了什么......内容只是为构造函数的调用而复制,在这种情况下,这意味着指定对象的地址被复制。如果您现在将另一个对象的新地址分配给 runner,为什么这会反映在您的 TestDI 实例中已经完成的副本中?我猜你脑子里有些东西搞混了 ;-)

Coming from C#, where objects are passed by reference (if they're not primitive types or structs). I've written some TypeScript code to test something:

嗯,是的,您可以将它们作为参考传递(例如,通过使用 ref),但默认情况下,地址只是简单地复制(如上所述)。

为了让您更轻松:只需复制并粘贴,惊喜不断

class Program
{
    static void Main(string[] args)
    {
        IRunner runner;
        runner = new FooRunner();

        TestDI SUT = new TestDI(runner);

        // Expected output: Foo
        // Actual output: Foo
        Console.WriteLine(runner.Run());

        // Expected output: Foo
        // Actual output: Foo
        SUT.Test();

        runner = new BarRunner();

        // Expected output: Bar
        // Actual output: Bar
        Console.WriteLine(runner.Run());

        // Expected output: Bar
        // Actual output: Foo
        SUT.Test();
    }
}


public interface IRunner
{
    string Run();
}

public class TestDI
{
    private readonly IRunner runner;

    public TestDI(IRunner runner)
    {
        this.runner = runner;
    }

    public void Test()
    {
        Console.WriteLine("Result of runner: " + this.runner.Run());
    }
}

public class FooRunner : IRunner
{
    public string Run()
    {
        return "Foo";
    }
}

public class BarRunner : IRunner
{
    public string Run()
    {
        return "Bar";
    }
}