javascript方法链中的输入参数是如何填充的?

2023-12-21

我正在尝试真正了解 javascript 工作原理的细节。在方法链接期间,有时一个方法会返回到另一个具有命名输入参数的方法。

例如,在 D3 中,模式如下所示:

d3.select("body").selectAll("p")
    .data(dataset)
    .enter()
    .append("p")
    .text(function(d) { return d; }); //what does this d refer to? How is it filled?

在 jquery 中,该模式如下所示:

$.ajax({
  ...
})
  .done(function( data ) {  //what does this data refer to? How is it filled? 

我从实际编码中知道这些输入参数的名称可以是任何名称。但是归档输入参数的数据从哪里来呢?它是否仅引用链中先前方法返回的数据?


两个不同的主题,所以我将分别解释它们:

使用函数作为方法参数

首先,更正:您给出的例子是not“一个方法返回到具有命名输入参数的另一个方法”的示例。它们是一个函数作为另一个方法的输入参数的示例。

为了澄清这一点,我将举一个例子,其中一个函数的返回值is用作另一个的输入。

var a = "Hello ",
    b = "World!";

var c = a.concat( b.toUpperCase() ); //c = "Hello WORLD!"

为了创造c,按顺序发生以下情况:

  1. 浏览器开始解析concat方法,但需要弄清楚给它什么参数。
  2. 该参数包括方法调用,因此toUpperCase()的方法b执行,返回字符串“WORLD!”。
  3. 返回的字符串成为参数a's concat()现在可以执行的方法。

concat()就方法而言,结果与您编写的结果相同c = a.concat("WORLD!")-- 它并不关心字符串“WORLD!”是由另一个函数创建的。

你可以说返回值 of b.toUpperCase()作为参数传递,并且not函数本身,因为函数名称末尾有括号。函数名称后面的括号告诉浏览器在计算出该函数的任何参数的值后立即执行该函数。Without在括号中,该函数被视为任何其他对象,并且可以作为参数或变量传递,而无需实际执行任何操作。

当一个函数object未执行的,用作另一个函数的参数,发生的情况完全取决于第二个函数内的指令。如果您将该函数对象传递给console.log(),函数的字符串表示形式将被打印到控制台,而不执行您传入的函数。但是,大多数接受另一个函数作为输入的方法都被设计为使用指定参数调用该函数。

一个例子是map()数组的方法。这map方法创建一个新数组,其中每个元素都是对原始数组的相应元素运行映射函数的结果。

var stringArray = ["1", "2!", "3.0", "?"];

var numberArray = stringArray.map(parseFloat); //numberArray = [1, 2, 3, NaN]

功能parseFloat()是一个内置函数,它接受一个字符串并尝试从中计算出一个数字。请注意,当我将其传递给映射函数时,我只是将其作为变量名传递,而不是在末尾加上括号来执行它。它由map函数执行,并且是map函数决定它获取什么参数。每次调用的结果parseFloat被分配的map函数到结果数组中的位置。

具体来说,map函数执行parseFloat with three参数:数组中的元素、该元素在数组中的索引以及整个数组。这parseFloat然而,函数仅使用一个参数,因此第二个和第三个参数将被忽略。 (如果你尝试做同样的事情parseInt,但是,您会得到意想不到的结果,因为parseInt does使用第二个参数——它将其视为整数的基数(“基数”)。)

map 函数不关心传入函数需要多少个参数,它当然也不关心该函数内部使用了哪些变量名。如果您自己编写地图函数,它看起来会像这样:

Array.prototype.myMap = function(f) {

    var result = [];

    for (var i = 0, n=this.length; i<n; i++) {

         result[i] = f( this[i], i, this);
                  //call the passed-in function with three parameters
    }
    return result;
};

The f函数被调用并给出参数,而不知道它是什么或它做什么。参数以特定的顺序给出——元素、索引、数组——但不链接到任何特定的参数名称。

现在,像这样的限制map方法的缺点是很少有Javascript函数可以直接调用,只是传递一个值作为参数。大多数函数都是特定对象的方法。例如,我们不能使用toUpperCase方法作为参数map, 因为toUpperCase仅作为字符串对象的方法存在,并且仅作用于该特定字符串对象,而不作用于映射函数可能为其提供的任何参数。为了将字符串数组映射为大写,您需要创建自己的函数,该函数以映射函数使用它的方式工作。

var stringArray = ["hello", "world", "again"];

function myUpperCase(s, i, array) {

     return s.toUpperCase(); //call the passed-in string's method

}

var uppercaseStrings = stringArray.map( myUpperCase );
   //uppercaseStrings = ["HELLO", "WORLD", "AGAIN"]

但是,如果您只想使用该功能myUpperCase这一次,您不需要单独声明它并给它命名。您可以直接将其用作匿名函数.

var stringArray = ["hello", "world", "again"];

var uppercaseStrings = stringArray.map( 
                           function(s,i,array) {
                               return s.toUpperCase();
                           }
                       );
   //uppercaseStrings still = ["HELLO", "WORLD", "AGAIN"]

开始看起来很熟悉吗?这是许多 d3 和 JQuery 函数使用的结构 - 您传入一个函数,作为函数名称或匿名函数,并且 d3/JQuery 方法在选择的每个元素上调用您的函数,传入指定值作为第一个、第二个和第三个参数。

那么参数名称呢?正如您提到的,它们可以是您想要的任何内容。我可以在我的函数中使用非常长的描述性参数名称:

function myUpperCase(stringElementFromArray, indexOfStringElementInArray, ArrayContainingStrings) { 

         return stringElementFromArray.toUpperCase();
}

传入函数的值将是相同的,纯粹基于映射函数传入它们的顺序。事实上,由于我从不使用索引参数或数组参数,所以我可以将它们排除在我的函数之外。函数声明并仅使用第一个参数。其他值仍然通过map,但它们被忽略了。然而,如果我wanted使用传入的第二个或第三个参数map,我必须为第一个参数声明一个名称,只是为了保持编号的直接性:

function indirectUpperCase (stringIDontUse, index, array) {

         return array[index].toUpperCase();
}

这就是为什么,如果你想使用 d3 中的索引号,你必须写function(d,i){return i;}。如果你刚刚这样做了function(i){return i;}的价值i将是数据对象,因为这就是 d3 函数始终作为第一个参数传递的内容,无论您如何称呼它。这是外部函数传入参数值。参数名称仅存在于内部函数内部。


必要的警告和例外:

  • 我说过,map 函数并不关心传入函数需要多少个参数。确实如此,但其他外部函数可以使用传入函数的.length属性来确定需要多少个参数并相应地传递不同的参数值。

  • 你不have命名函数的参数以便访问传入的参数值。您还可以使用以下方式访问它们arguments在该函数内列出。因此编写大写映射函数的另一种方法是:

    function noParamUpperCase() {
    
           return arguments[0].toUpperCase();
    }
    

    但是,请注意,如果外部函数使用参数数量来确定要传递给内部函数的值,则该函数将显示为不接受任何参数。


方法链接

您会注意到上面我没有提到方法链接。这是因为它是一个完全独立的代码模式,恰好也在 d3 和 JQuery 中大量使用。

让我们回到第一个示例,它创建了“Hello WORLD!”出自“你好”和“世界!”。如果您想创建“HELLO World!”怎么办?反而?你可以做

var a = "Hello ",
    b = "World!";

var c = a.toUpperCase().concat( b ); //c = "HELLO World!"

创建时发生的第一件事c is the a.toUpperCase()方法被调用。该方法返回一个字符串(“HELLO”),与所有其他字符串一样,它有一个.concat()方法。所以.concat(b)现在被称为该方法返回的字符串,不是原始字符串a。结果是b连接到大写版本的末尾a: “你好世界!”。

在这种情况下,返回值是new与起始对象类型相同的对象。在其他情况下,它可能是完全不同类型的数据。

var numberArray = [5, 15];

var stringArray = numberArray.toString().split(","); //stringArray = ["5", "15"]

我们从一组数字开始,[5,15]。我们称该数组为toString()方法,它生成数组的格式良好的字符串版本:“5,15”。该字符串现在拥有所有可用的字符串方法,包括.split(),它将字符串拆分为围绕指定拆分字符(在本例中为逗号)的子字符串数组。

您可以将其称为方法链接类型,即调用另一个方法返回的值的方法。然而,当使用方法链来描述 Javascript 库的功能时,关键在于方法的返回值是调用该方法的同一个对象.

所以当你这样做时

d3.select("body").style("background", "green");

The d3.select("body")方法创建一个 d3 选择对象。该对象有一个style()方法。如果你使用 style 方法set一种样式,您实际上不需要从中返回任何信息。它本可以被设计为根本不返回任何值。相反,它返回该方法所属的对象(this目的)。所以您现在可以调用该对象的另一个方法。或者你可以将它分配给一个变量。或两者。

var body = d3.select("body").style("background", "green")
                            .style("max-width", "20em");

但是,您始终必须了解哪些方法don't返回相同的对象。例如,在很多 d3 代码示例中您会看到

var svg = d3.select("svg").attr("height", "200")
                          .attr("width", "200")
                          .append("g")
                          .attr("transform", "translate(20,20)");

现在,该方法append("g") doesn't返回相同的选择<svg>元素。它返回一个new选择包括<g>元素,然后赋予它一个转换属性。分配给变量的值svg is the last从链中返回值。所以在后面的代码中,你必须记住变量svg实际上并不是指选择<svg>元素,但对于<g>。我觉得这很令人困惑,所以我尽量避免使用变量名svg对于实际上不是的选择<svg>元素。

当然,任何 d3.attr() or .style()方法可以将函数而不是字符串作为第二个参数。但这不会改变方法链的工作方式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

javascript方法链中的输入参数是如何填充的? 的相关文章

随机推荐

  • 如何使用 jQuery 更改多个元素的样式?

    我有一个 CSS 样式表 其规则如下 h1 h2 h3 h4 contentheading title font size 13px font weight normal font family Arial Geneva Helvetica
  • AsyncValidators 会一直触发吗?

    我正在使用 angular js 1 6 4 版本 我创建了一个用于服务器端验证的指令 我发现它在加载表单时触发 这是错误的 我只想在更改值时触发我的代码 我的 HTML 代码是 div class col xs 6 div class c
  • 在 Android 中将外部缓冲区导入 Vulkan 时出现问题

    我正在尝试使用 Vulkan 在 Android 10 中显示图像 管道看起来像这样 MediaCodec gt ImageReader gt AHardwareBuffer 传递到 Vulkan 上下文 gt 映射到 Vulkan gt
  • 如何更改 Android 上浮动操作按钮 (FAB) 的形状?

    在我们的 Android 应用程序中 我们需要创建一个浮动操作按钮 它不是默认的圆形 而是带有三个圆角的正方形 该晶圆厂如下图所示 我设法创建了这样一个表单 但不知道如何将其应用到我的工厂 或者是否可能 形状的 xml 文件如下所示
  • Jenkins 中的 Gerrit-trigger 插件如何工作?

    我想了解 Jenkins 中的 gerrit trigger 是如何详细工作的 另外 如何调用触发条件的测试 Thanks gerrit 触发器的工作原理如下 它使用 ssh 连接到 gerrit 服务器并使用 gerrit stream
  • 按下按钮时在滚动区域中加载 QTableWidgets

    我有一个名为 test 的方法 它将 3 个单行表加载到滚动条中 然而 由于某种原因 我无法弄清楚 如果我只是在加载时激活 test 它就可以工作 但如果我将其注释掉 然后尝试通过按下按钮来激活它 它就不起作用 这是主模块 带有 test
  • 迭代 *args?

    我正在编写一个脚本 我需要接受多个参数 然后迭代它们以执行操作 我开始定义一个函数并使用 args 到目前为止 我有如下内容 def userInput ItemA ItemB args THIS ItemA THAT ItemB MORE
  • DocumentDb - 嵌套文档和根级别的查询

    提醒我 编辑 删除 变更类型 问题 您不能对自己的帖子进行投票 0 你好 假设我有以下方式的文档 id 123 tags name something 我想查询包含 name searched 标签或 id 9000 的所有文档 我在操场上
  • ajax中的非法调用错误(Jquery 1.7.1)

    我正在尝试使用 jquery 发布 ajax 请求 var peName document getElementById peName value var peSubName document getElementById peSubNam
  • 通过 Visual Studio 进行 C++ 调试 - 向量大小变化的观察点

    我想用我的向量探索这些变化 因此我想在向量大小上设置一个点 因此 Visual Studio 将让我在每次大小更改后查看向量中的内容 我怎样才能做到这一点 在此链接中 http www codeproject com Articles 35
  • C# 如何在 windows xp/7 中禁用屏幕键盘声音

    我有一个在 Windows XP 7 上运行的 C 应用程序 我使用屏幕键盘 启用声音时会出现延迟 从而导致问题 我想禁用声音 如何通过我的 C 应用程序代码禁用声音 有任何想法吗 您可以从注册表禁用它 HKEY CURRENT USER
  • Apache hive 错误 此版本的 hadoop 不支持合并凭据

    我使用的是hadoop 1 2 1 hbase 0 94 14和hive 1 0 0 我的集群中有三个数据节点 还有三个区域服务器 我必须将一些数据从 hbase 导入到 hive 我已经成功配置配置单元 但是当我运行命令计数 no 时 h
  • 从 Xcode 5 导入 SVN 中的项目

    在 xcode 4 管理器中有一个 导入 按钮 在 xcode5 中如何导入 svn 存储库中的项目 thanks 这个问题有点令人困惑 所以如果这不完全是您所需要的 请告知 否则 请随意接受答案 令人困惑的是 您描述的 Xcode 4 工
  • 哪个版本的 Maven 与 Java 6 兼容?

    我必须在一个需要 java 6 才能运行的旧项目中工作 因为其中引用了已在未来版本中删除的已折旧的 sun 类 作为该过程的一部分 我将系统路径中的 jdk 从 8 更改为指向 java 6 jdk 这样做之后我得到 Exception i
  • EaselJS - 拖动缩放父级的子级

    注意 此问题现已解决 请参阅下面我的回答中的 修复 如果您认为合适 请随意注入任何进一步的知识 首先 我一直在研究和谷歌搜索 localToGlobal localToLocal 和 globalToLocal 但我对这些方法的理解还不足以
  • 无法将地图放入接收器上下文中

    我正在尝试查看在接收器上下文中抛出地图的方法 在这段代码中 class Sunk has titanic method sink say Sinking titanic Sunk new titanic for 1 3 1 3 map Su
  • 返回时未调用 ngOnInit

    我注意到ngOnInit 当我返回到已经实例化的页面时 方法不会被调用 我必须使用其他方法吗 我需要一个每次访问特定页面时都会调用的方法 EDIT已经测试过onPageWillEnter 但它在 Ionic 2 中没有被触发 Check 生
  • PHP中的短语分割算法

    不知道如何解释 让我们举个例子 说我想拆分句子 今天是个好日子 into today today is today is a today is a great today is a great day is is a is a great
  • 如何将图像调色板缩小为特定颜色?

    我正在使用 Python 程序来创建十字绣方案 并且需要将图像中的颜色减少为特定的牙线颜色像这样 http www dmc usa com Products Needlework Threads Embroidery Threads med
  • javascript方法链中的输入参数是如何填充的?

    我正在尝试真正了解 javascript 工作原理的细节 在方法链接期间 有时一个方法会返回到另一个具有命名输入参数的方法 例如 在 D3 中 模式如下所示 d3 select body selectAll p data dataset e