Javascript绑定到对象

Javascript绑定到对象,javascript,Javascript,我尝试了这个例子,当我这样做时,我得到了以下消息未定义的岩石而不是红宝石。 你能解释一下原因吗。函数执行上下文和this关键字 JavaScript函数在调用时有一个执行上下文,使得this关键字绑定到调用它们的对象。如果调用john.says()函数的执行上下文将有一个this关键字指向john。如果将全局变量func指定给对象john上的方法表示,则已将执行上下文更改为全局对象。调用func函数时,此将取消对窗口的引用(或未定义的*),并且由于窗口.skill未定义,表示将强制将该值转换为字

我尝试了这个例子,当我这样做时,我得到了以下消息
未定义的岩石而不是
红宝石。
你能解释一下原因吗。

函数执行上下文和
this
关键字 JavaScript函数在调用时有一个执行上下文,使得
this
关键字绑定到调用它们的对象。如果调用
john.says()
函数的执行上下文将有一个
this
关键字指向
john
。如果将全局变量
func
指定给对象
john
上的方法
表示
,则已将执行上下文更改为全局对象。调用
func
函数时,
将取消对
窗口的引用(或
未定义的
*),并且由于
窗口.skill
未定义,
表示
将强制将该值转换为字符串,以将其与字符串“rocks!”连接起来

如何使用bind保证执行上下文 您可以将函数的副本绑定到对象(有效地锁定其上下文引用):

如何使用闭包保证执行上下文 或者,您可以通过在构造函数中使用闭包来关闭相关位:

var func = john.says.bind(john);
如何使用闭包保证值 您可以直接从方法中引用
skill
值,因此根本不需要上下文:

function Developer(skill){
  var _this = this; // we keep a reference here
  this.skill = skill;
  this.says = function(){
    alert(_this.skill + ' rocks!'); 
    // when invoked _this refers to the context at construction
  }
  return this;
}
如何使用call和apply在调用时保证执行上下文 最后一个选项是在调用时使用所需的上下文调用该方法:

function Developer(skill){
  // because skill is defined in this context, says will refer to this context
  // to get the value of the skill variable.
  this.says = function(){
    alert(skill + ' rocks!');
  }
}
如何使用原型来允许动态执行上下文设置正确的 如果我们想在对象实例或类型之间重用方法,但在调用时具有正确的执行上下文,那么可以使用prototype属性

func.call(john /*, optional arguments... */);
func.apply(john /*, optional arguments as an array */);
更多阅读:
  • 执行上下文规范:
  • MDN文档关于此:
*“use strict”激活一个表示JavaScript未来的特殊strict模式。当未设置上下文时,此特殊的严格执行环境将不会解析为全局对象,而是将其解析为适当范围的值
未定义

,因为
func()
仅具有该函数,而不具有任何其他相关信息。
(This.skill)

上下文丢失了
调用
says()
时,此
引用了
john

但是现在,当您调用
func()
时,此
指的是
窗口
。因此,
this.skills
将返回
undefined
,除非您有一个同名的全局变量。

试试这个

function Developer(skill){
  this.skill = skill;
  this.says();
}

Developer.prototype.says = function(){
  alert(this.skill + ' rocks!');
}

var john = new Developer("Ruby"); // alert("Ruby rocks!")
var tony = new Developer("JavaScript");  // alert("JavaScript rocks!")
工作演示

  • 调用函数时,
    将引用调用函数的对象

  • 当你说

    function Developer(skill) {
        this.skill = skill;
        this.says = function() {
            alert(this.skill + ' rocks!');
        }
    }
    var john = new Developer('Ruby');
    john.says();
    
    您只是得到函数对象(它不记得定义它的对象)

  • 当你调用函数时,就像这样

    var func = john.says;
    
    func();
    
    没有调用
    func
    的当前对象。因此,默认情况下,JavaScript将全局对象(
    window
    浏览器中的对象)指定为
    this
    。由于在全局对象中未定义
    skill
    ,因此返回
    undefined

  • 注意:在严格模式下,
    如果没有当前对象,此
    将是
    未定义的

    这就是为什么我们必须显式地将对象绑定到函数,如下所示

    var func = john.says;
    
    func();
    

    Function.prototype.bind
    将返回一个绑定到
    john
    的新函数。因此,当您调用此
    时,此
    将引用
    john
    让我们通过实际返回对象来说明发生了什么:

    func.bind(john)();
    
    好吧,那为什么我们没有定义呢?好吧,一旦我们删除了函数,它就不再有上下文-它不知道这是什么。如果我们要这样做:

    function Developer(skill) {
      this.skill = skill;
      this.says = function() {
        alert(this.skill + ' rocks!');
      }
      return this; //this is basically { skill: skill, says: function() {} }
    }
    
    var john = new Developer('Ruby');
    var func = john.says; // all it knows is the function() part, has no knowledge of skill
    func(); //undefined rocks!
    
    然后我们传入John作为
    这个
    参数。解决方法是,在创建函数时将值传递给函数:

    func.apply(john);
    
    函数开发人员(技能){
    这个技能=技能;
    
    this.says=function(skill){/保持上述模式的最快方法是将
    this
    直接绑定到方法
    this.says=function(){…}.bind(this);


    。它已经以“在大多数情况下,
    this
    的值取决于函数的调用方式”开头。也许下面的答案可以帮助您理解JavaScript原型和构造函数。虽然这可能最终“解决”OP的问题,但它并没有回答他的问题。“
    this
    不再指
    john
    对象”是迂腐的,它从一开始就没有指
    john
    ,因为它在函数调用之前根本不存在。@FelixKling,我已经更新了我的答案。“迂腐”是什么意思“?哦,我的意思是,我在批评一件其他人可能根本没有注意到的小事;)当通过
    new
    关键字创建对象时,调用意味着将返回新创建的上下文对象。因此,您不需要“需要”在开发人员方法的底部返回它(尽管这不会影响安全性)。
    function Developer(skill) {
        this.skill = skill;
        this.says = function () {
            alert(this.skill + ' rocks!');
        }.bind(this);
    }
    var john = new Developer('Ruby');
    var func = john.says;
    func(); // Ruby rocks!