【问题标题】:How to call Javascript method in the same file?如何在同一个文件中调用 Javascript 方法?
【发布时间】:2020-02-21 00:13:00
【问题描述】:

我有这样的代码:

mycode.js:

export default {
  foo() {
    return "foo";
  },
  bar() {
    return "bar" + this.foo();
  }
}

其他代码.js:

import mycode from "mycode.js";

mycode.bar();  // usually works fine, returns "barfoo"

不过,我在箭头函数中调用 mycode.bar() 时遇到了困难。问题是 bar() 中的“this”不再指代 mycode 中的对象,而是指调用者的上下文。

如果我想继续使用这种代码风格来定义函数并导出它们,如何在 bar() 中调用 foo()?

我尝试将 mycode 中的方法绑定()到导出的对象,但据我所知,您必须为每个方法单独执行此操作。

我也尝试在我的代码顶部这样做:

let self = this;

然后引用“self.foo()”,但是“this”在我将它分配给self时没有定义。

我可以完全改变代码风格。我可以像这样定义每个函数:

mycode.js

function foo() {
  return "foo";
}

export default {
  foo, bar, ...
}

但是我必须单独命名每个函数。

一定有更好的方法。

【问题讨论】:

  • 正确命名有什么问题? JIT 解析器当然不会因此而评判您,因此,如果它使您的代码更易于阅读和使用:这不正是我们都需要的代码吗?

标签: javascript


【解决方案1】:

问题不在于您如何导出;这就是 this 在 JavaScript 中的工作方式。如果您在作为方法的上下文之外引用函数,则方法的主体将不会具有一致的this,除非您显式绑定它,并且除非有要绑定的标识符,否则您将无法绑定任何东西.例如,您可以这样做:

const mod = {
  foo() {
    return "foo";
  },
  bar() {
    return "bar" + this.foo();
  }
};

mod.foo = mod.foo.bind(mod);
mod.bar = mod.bar.bind(mod);

export default mod;

...但我敢肯定,这几乎没有您想要的简洁性。如果您使用类和支持类属性的 JS 版本,另一种选择是:

class MyModule {
  foo: () => "foo";
  bar: () => "bar" + this.foo();
}

export default new MyModule();

就个人而言,虽然我不了解您的全部情况,但我认为命名导出更有意义,并且使用模块闭包而不是 this

export function foo() {
  return "foo";
}

export function bar() {
  return "bar" + foo();
}

【讨论】:

    【解决方案2】:

    如果您使用命名导出而不是默认导出,则可以引用您要导出的对象的名称,例如:

    export const myMethods = {
      foo() {
        return "foo";
      },
      bar: () => {
        return "bar" + myMethods.foo();
      }
    };
    

    确保也将导入更改为命名导入:

    import { myMethods } from 'mycode.js';
    

    can also 导入当前模块(感谢 Bergi),虽然它看起来非常奇怪:

    import myMethods from './mycode.js'; // <--- THE CURRENT FILE
    export default {
      foo() {
        return "foo";
      },
      bar: () => {
        return "bar" + myMethods.foo();
      }
    }
    

    默认导出的一个更大问题是无法引用您正在导出的内容,除非您像上面那样导入当前模块。如果您使用默认导出并且该函数是箭头函数,this 将从模块的外部范围继承,因此您导出的对象不能被引用像上面这样一个奇怪的 hack。

    【讨论】:

    • 非常聪明。谢谢。
    【解决方案3】:

    您可以表达或声明您的函数,在文件中内部使用它们,然后决定将哪些函数公开(导出)。

    命名导入

    由于使用通配符可以获得更大的有效负载并添加不需要的保密层,因此您最好始终命名您想要导入的所需方法

    通过使用 { 命名 } 导入列表,不再有 as &lt;alias&gt; 指针,使 this 结果为 undefined

    PS:导出属性时get rid of the default

    // foo.mjs
    
    function foo() {
      return "foo";
    }
    
    function bar() {
      console.log(this);    // undefined 
      return "bar" + foo();
    }
    
    export {
      foo,
      bar
    }
    

    使用表现力 命名导入

    // index.mjs
    
    import { bar } from './foo.mjs';
    
    console.log(bar()); // "barfoo"
    

    运行$ node --experimental-modules ./index.mjs,你会在日志中看到"barfoo"


    通配符导入* as alias

    小心:通配符导入会将this引用到常量as 别名导入[Module]

    // foo.mjs
    
    function foo() {
      return "foo";
    }
    
    function bar() {
      console.log(this) // [Module] { bar: [Function: bar], foo: [Function: foo] }
      return "bar" + this.foo(); // `this` points to the importing [Module] alias
      // ANTIPATTERN, and can result in undefined if imported as a named list
    }
    
    export {
      foo,
      bar
    }
    
    // index.mjs
    
    import * as test from './foo.mjs';
    
    console.log(test.bar()); // "barfoo"
    

    脆弱,容易出错,因为如果使用像 import { bar } from "./foo.mjs"; console.log(bar()); 这样的命名导入可能会导致

    TypeError: 无法读取未定义的属性 'foo'

    应该避免。

    链接:

    https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

    https://humanwhocodes.com/blog/2019/01/stop-using-default-exports-javascript-module/
    https://github.com/airbnb/javascript/issues/710

    【讨论】:

    • 谢谢。这是我尝试的最后一件事,但我在问是否有一种方法可以保持相同的代码样式,即 export default { foo() {}, ... }
    • 我只是根据您的建议重写了我的代码。它确实有效。它还具有代码在外部看起来相同的优点,因此我不必修改应用程序其他部分的任何内容。
    • @ccleve 你有一些有趣的方法(来自答案),但这是保持清洁和简单的美妙之处。 foo() 是文件范围内的函数(或方法,如果需要)。在精神上,您可以像对待 this.foo() 一样对待它,但没有 this :)
    猜你喜欢
    • 2011-01-15
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 2011-02-01
    • 2021-11-20
    • 2023-01-16
    相关资源
    最近更新 更多