首页 > 解决方案 > 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接口的一个实例传递给了一个类 c-tor,然后,我的类的一个字段填充了我在 c-tor 中传递的任何内容。

稍后在代码中,我更改了传递给 c-tor 的变量,但是,当我调用类的test函数Runner字段时,似乎没有反映在创建类的实例时对传递的原始变量所做的任何更改TestDI

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

这是怎么回事?

标签: javascripttypescriptpass-by-reference

解决方案


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

不是真的...如果您将上面的代码转换为 C# 代码并运行它,您将看到它的行为与您的 TypeScript 代码完全相同。

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

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

是的,您可以将它们作为参考传递(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";
    }
}

推荐阅读