分配后,JavaScript函数绑定(此关键字)将丢失

时间:2010-04-23 21:07:55

标签: javascript

这是JavaScript中最神秘的功能之一,在将对象方法分配给其他变量后,绑定(此关键字)丢失

var john = {
  name: 'John',
  greet: function(person) {
    alert("Hi " + person + ", my name is " + this.name);
  }
};

john.greet("Mark"); // Hi Mark, my name is John

var fx = john.greet;  
fx("Mark"); // Hi Mark, my name is 

我的问题是:

1)作业背后发生了什么? var fx = john.greet;    是按价值复制还是按参考复制?    fx和john.greet指向两个不同的功能,对吧?

2)由于fx是一个全局方法,因此范围链仅包含全局对象。 Variable对象中 属性的值是多少?

5 个答案:

答案 0 :(得分:13)

john.greet("Mark")实际上调用了一个函数。当您执行var fx = john.greet;时,您将获得对该功能的引用。因此,当您调用它时,this不会绑定到john。您实际执行的操作是window.fx("Mark"),因此thiswindow对象。当你说它处于全球范围内时,你走在了正确的轨道上。在此特定实例中,全局对象为window,因此fx实际为window.fx

如果要设置功能参考,则应使用callapply,如果要设置this的值。试着这样做:

fx.call(john, "Mark");

callapply中的第一个参数是函数调用上下文中this使用的值。

修改

有些人提到这里的真正问题可能是围绕对象文字与对象实例的混淆。您正在创建一个对象文字,其行为也类似于单身。您无法创建该对象的新实例。在这种情况下,john是对该对象文字的引用。在该上下文中,函数this中的greet指的是对象文字本身。因此,当您致电john.greet("Mark")时,this绑定到john

当您单独获取对john.greet的引用并将其分配给全局变量时,您基本上就是这样做:

var fx = function(person) {
   alert("Hi " + person + ", my name is " + this.name);
}

在这种情况下,thiswindow,因为fx基本上是window.fx(因为此处的全局对象是window。假设此代码已被包装在另一个函数中,全局对象将引用该函数。

如果要创建对象的多个实例,可以执行以下操作:

var Person = function(name) {
    var self = this; //maintains a reference to the instance

    this.name = name;
    this.greet = function(name) {
        alert("Hi " + name + ", my name is " + self.name);
    }
}

var john = new Person("John");
john.greet("Mark"); // alerts "Hi Mark, my name is John"

var fx = john.greet;
fx("Mark"); // also alerts "Hi Mark, my name is John"

这里,self变量(函数的本地变量)维护对实际实例的引用,因为在创建对象时它将它绑定到this

在Javascript中有许多与OOP相关的最佳实践。你可以谷歌找出(有很多链接)。我建议特别是从道格拉斯·克罗克福德那里读书。

答案 1 :(得分:6)

1)fxjohn.greet指的是同一个函数对象,对象的赋值操作,按引用工作

对于原始值,例如StringNumberBoolean undefinednull,将会复制该值。

2)this值指的是全局对象。

this值不是Variable Object的属性,它与范围链无关,是一个特殊的保留字,并且是隐式确定的当function is called时(您也可以通过callapply明确设置)。

JavaScript内部处理Reference type,它由两个组件组成,基础对象属性名称,当调用函数时,GetValue 1}}值是通过获取基础对象(通过内部new操作)隐式确定的。

最后,隐式设置this的最后一种情况是,当您使用{{3}}运算符调用函数时,this关键字将引用新创建的对象。

简而言之,以下是this隐式 的工作方式

1-当函数作为方法调用时(该函数作为对象的成员被调用):

this

2- 正常函数调用:

obj.method(); // 'this' inside method will refer to obj

3-使用myFunction(); // 'this' inside the function will refer to the Global object // or (function () {})(); 运算符时:

new

答案 2 :(得分:3)

据我了解,您只是将该方法分配给变量“fx”。 john对象的上下文并没有随之而来。

在我的脑海中,在fx的上下文中“this”将引用全局对象,在浏览器的上下文中(我相信)等同于您的窗口对象。

(编辑以澄清全局对象。排序)

答案 3 :(得分:1)

因为你只是将fx设置为greet方法而不是整个john对象,所以它没有它的父级概念,并且变为全局范围。所以从本质上说,它只是通过复制方法传递价值。

由于该函数现在是全局范围的,因此“this”成为Window对象。

如果你改为将fx设置为john,你会得到预期的结果。

var john = {
  name: 'John',
  greet: function(person) {
    alert("Hi " + person + ", my name is " + this.name);
  }
};

john.greet("Mark"); // Hi Mark, my name is John

var fx = john;  
fx.greet("Mark"); // Hi Mark, my name is John

答案 4 :(得分:0)

受到@Vivin Paliath回答的启发,实际上我想出了一些新东西。至于我,我总是尽力使javascript编程与java相同,尤其是在OOP中。

所以我的建议是尽可能避免在我们第一次使用时这个

var self = this;

我们应该在所有函数(原型函数,无论如何)中使用self而不是this,但如果我们写这样的东西:

function MyObject = {
     var self = this;
};

MyObject.prototype = {
     method1 = function(data){
         self.data = data;
     }
}

这不起作用,因为原型是MyObject中的一个对象,它无法访问MyObject拥有的私有成员 self 。我的解决方案很简单:

function MyObject = {
     var self = this;
     MyObject.prototype.method1 = function(data){
         self.data = data;
     };
}

这有利于原型的效率,而且我们也不必关心所有这个问题。虽然我们会输入很多 MyObject.prototype.xxxx 的东西。

如果这对你们有帮助,请给我一些大拇指,这样我就可以在大拇指中获得15点声望,谢谢。