草庐IT

javascript - 当您将 'this' 作为参数传递时?

coder 2024-07-26 原文

这个问题在这里已经有了答案:





How does the "this" keyword work?

(21 个回答)


6年前关闭。




我正在尝试了解 this ,这让我有点困惑:

var randomFunction = function(callback) {
    var data = 10;
    callback(data);
};

var obj = {
    initialData:  20,
    sumData: function(data) {
        var sum = this.initialData + data;
        console.log(sum);
    },
    prepareRandomFunction: function() {
        randomFunction(this.sumData.bind(this));
    }
};

obj.prepareRandomFunction();
this旨在将自身设置在代码中首次呈现的位置?
例如,在我的示例中,我成功地使用它来引用 obj并将函数绑定(bind)到 obj ,但由于 this正在作为回调函数传递,是什么阻止它被设置为 randomFunction (即是什么阻止它从字面上传递“this.sumData.bind(this)”,以便 this 在从那里被调用时设置为 randomFunction)?
更新
我并不是在问这通常是如何工作的(我不认为)。我主要是想知道为什么this在我将其定义为我的 randomFunction 的参数的地方被设置打电话,而不是在哪里callbackrandomFunction 内被调用.
我可能是错的,但如果我要交换 this.sumData.bind(this)callback(data)我目前拥有的我认为我会得到不同的结果。是不是因为callback是对 this.sumData.bind(this) 的引用它是什么时候第一次定义的(在哪里 thisobj )?

我想我已经通过这个场景了解到 this执行时设置。它不会作为参数传递,以便稍后在该参数被调用时进行设置。

最佳答案

this在函数调用内部根据函数的调用方式设置。 this主要有六种方式设置。

  • 普通函数调用:在正常的函数调用中,例如 foo() , this设置为全局对象(浏览器中的 window 或 nodejs 中的 global)或 undefined (在 JavaScript 的严格模式下)。
  • 方法调用:如果一个方法被调用,例如 obj.foo()其中方法foo是使用 function 的普通方法声明关键字或对 class 使用常规方法声明语法,然后 this设置为 obj函数内部。
  • .apply() 或 .call(): .apply().call()被使用,然后 this根据传递给 .apply() 的内容设置或 .call() .例如,你可以做 foo.call(myObj)并导致 this设置为 myObj内部 foo()对于那个特定的函数调用。
  • 使用新的:如果您使用 new 调用函数如 new foo() ,然后创建一个新对象和构造函数 foothis 调用设置为新创建的对象。
  • 使用 .bind(): 使用时 .bind()从内部使用 .apply() 的调用返回一个新的 stub 函数设置 this传递给 .bind() 的指针.仅供引用,这并不是真正的不同情况,因为 .bind()可以通过 .apply() 实现.
  • 使用 ES6胖箭头函数 在 ES6+ 中通过箭头语法定义一个函数将绑定(bind)当前的词法值 this到它。因此,无论在其他地方如何调用该函数(使用之前的任何调用方式),this value 将由解释器设置为值 this在定义函数时有。这与所有其他函数调用完全不同。

  • 有第七种方法,通过 回调函数 ,但它实际上并不是它自己的方案,而是调用回调的函数使用上述方案之一,这决定了 this 的值。将在调用回调时。您必须查阅文档或调用函数的代码或自行测试以确定是什么 this将在回调中设置为。

    在 JavaScript 中需要理解的重要一点是 JavaScript 中的每个函数或方法调用都会为 this 设置一个新值。 .并且,设置哪个值取决于函数的调用方式。
    因此,如果您将方法作为普通回调传递,默认情况下该方法不会被调用为 obj.method()因此不会有 this 的正确值设置它。您可以使用 .bind()解决这个问题。
    了解某些回调函数(例如 DOM 事件处理程序)使用特定值 this 调用也很有用。由调用回调函数的基础设施设置。在内部,他们都使用 .call().apply()所以这不是一个新规则,而是需要注意的事情。回调函数的“契约”可能包括它如何设置 this 的值。 .如果没有明确设置this的值,那么它将根据规则 #1 进行设置。
    在 ES6 中,通过箭头函数调用函数,维护当前词法值 this .这是维护词法 this 的数组函数的示例from MDN :
    function Person(){
      this.age = 0;
    
      setInterval(() => {
        this.age++; // |this| properly refers to the person object
      }, 1000);
    }
    
    var p = new Person();
    

    您的 obj.prepareRandomFunction(); 示例是上面的规则 #2 所以 this将设置为 obj .
    您的 randomFunction(this.sumData.bind(this)) 示例是上面的规则 #1 所以 this内部 randomFunction将设置为全局对象或 undefined (如果在严格模式下)。
    由于 randomFunction 正在调用一个回调函数,该函数本身使用了 .bind() ,那么 this 的值回调函数内部调用时会被设置为this的值传递给 .bind()this.sumData.bind(this)就像上面的第 5 条规则一样。 .bind()实际上创建了一个新函数,它的工作是在设置自定义值 this 之后调用原始函数。 .

    以下是有关该主题的其他一些引用资料:
    How to avoid "this" refering to the DOM element, and refer to the object
    A better understanding of this
    How does the "this" keyword work?

    请注意,使用 .apply().call().bind() ,您可以创建各种有点奇怪的东西,有时甚至是非常有用的东西,而这些东西在 C++ 之类的东西中是永远无法完成的。 .您可以使用世界上的任何函数或方法,并像调用其他对象的方法一样调用它。
    例如,这通常用于复制 arguments 中的项目。对象到数组中:
    var args = Array.prototype.slice.call(arguments, 0);
    
    或类似:
    var args = [].slice.call(arguments, 0);
    
    这需要数组的 .slice()方法并调用它,但为它提供了一个参数对象作为 this指针。 arguments对象(虽然不是实际的数组),具有足够的类似数组的功能,.slice()方法可以对其进行操作,它最终会复制 arguments items 到一个实际数组中,然后可以直接使用实际数组操作对其进行操作。这种诡计不能随意完成。如果数组 .slice()方法依赖于 arguments 上不存在的其他数组方法对象,那么这个技巧是行不通的,但因为它只依赖于 [].length ,其中arguments对象有,它确实有效。
    因此,这个技巧可用于从任何对象“借用”方法并将它们应用到另一个对象,只要您应用它们的对象支持该方法实际使用的任何方法或属性。这不能在 C++ 中完成,因为方法和属性在编译时是“硬绑定(bind)”的(甚至 C++ 中的虚拟方法都绑定(bind)到在编译时建立的特定 v-table 位置),但可以在 JavaScript 中轻松完成,因为属性和方法在运行时通过它们的实际名称实时查找,因此任何包含正确属性和方法的对象都将与对这些进行操作的任何方法一起使用。

    关于javascript - 当您将 'this' 作为参数传递时?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28016664/

    有关javascript - 当您将 'this' 作为参数传递时?的更多相关文章

    1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

      我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

    2. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

      我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

    3. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

      我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

    4. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

      exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

    5. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

      在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

    6. ruby - RSpec - 使用测试替身作为 block 参数 - 2

      我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

    7. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

      我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

    8. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

      我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

    9. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

      我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

    10. ruby - 检查方法参数的类型 - 2

      我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

    随机推荐