Javascript对象如何工作?

时间:2011-07-15 18:17:59

标签: javascript

前言

  1. 我知道这些示例的正确代码。
  2. 我想知道的是为什么以下示例无法按预期工作。
  3. 代码

    • 在调用sayIt函数时使用括号。

      function Fruit(type){
          this.type = type;
          this.taste = "Awful";
          this.thought = sayIt();
      }
      
      function sayIt(){
          return this.taste+" "+ this.type;
      }
      
      window.onload = function (){
          var lemon= new Fruit("Lemon");
          alert(lemon.thought);
      };
      

      这会提醒“undefined undefined”,为什么?

    • sayIt没有括号的功能。

      function Fruit (type){
          this.type = type;
          this.taste = "Awful";
          this.thought = sayIt;
      }
      
      function sayIt(){
          return this.taste +" "+ this.type;
      }
      
      window.onload = function (){
          var lemon= new Fruit("Lemon");
          alert(lemon.thought);
      };
      

      这会在警告框中写下这个函数,为什么?

    提前谢谢。

7 个答案:

答案 0 :(得分:4)

注释内联,下面的讨论,参考资料以及最后的进一步阅读:

  • 在调用sayIt函数时使用括号。

    function Fruit(type){
        this.type = type;
        this.taste = "Awful";
        // Here, you're *calling* the `sayIt` function and assigning its
        // return value to `this.thought`. During the call, `this` will
        // refer to the global object (not to the `Fruit` instance).
        this.thought = sayIt();
    }
    
    function sayIt(){
        // If this is called as it is above, `this` is the global object,
        // which is `window` in browsers. Since `window` doesn't have
        // `taste` or `type` properties, this returns "undefined undefined".
        // That's what `this.thought` above receives.
        return this.taste+" "+ this.type;
    }
    
    window.onload = function (){
        var lemon= new Fruit("Lemon");
        // You've said this alerts "undefined undefined", but I think you'll
        // find it just alerts "undefined" (singular). There is no `sayIt`
        // property on the `lemon` instance at all. If you alerted
        // `lemon.thought` instead, you'd see the "undefined undefined" we
        // stored there above.
        alert(lemon.sayIt);
    };
    
  • sayIt没有括号的功能。

    function Fruit (type){
        this.type = type;
        this.taste = "Awful";
        // Here you're assigning the `sayIt` function to `this.thought`.
        // Perfectly normal stuff.
        this.thought = sayIt;
    }
    
    function sayIt(){
        return this.taste +" "+ this.type;
    }
    
    window.onload = function (){
        var lemon= new Fruit("Lemon");
        // Here you're also *referring* to the function object, not calling
        // it. (To call a function, you use `()` after it.) So since functions
        // are objects, you're passing an object reference into `alert`.
        // Alert will try to convert that to a string, and the
        // implementation of `toString` on `Function` objects in most
        // environments is to dump out a version of the source code of
        // the function (although this behavior is *not* standardized and
        // some browsers, esp. mobile browsers, don't do it).
        alert(lemon.thought);
    };
    

以上的关键概念:

  1. 功能是对象。您通过使用对()的引用,然后x = foo(); 调用函数,例如:

    foo

    表示“致电x并将其返回值指定给()”。

    仅使用 sans x = foo; 的名称​​将引用到函数对象,例如:

    foo

    表示“将函数对象x分配给x()。(然后您可以调用它:this。)

  2. 与其他一些语言不同,在JavaScript中,foo()完全由如何调用函数定义,而不是定义。当您通过自由变量(例如this)调用函数时,您无法为函数调用显式设置this,因此window将是默认值,这是全局对象(浏览器上的this)。

    您可以通过两种不同的方式设置// To put it on whatever `this` is at the moment: this.thought = sayIt; // Or to put it on an object we have in the variable `x`: x.thought = sayIt;

    一个。将函数引用放在object属性上,并通过属性对它的引用来调用函数,例如:

    this.thought();
    x.thought();
    

    然后您可以通过该属性调用它:

    this

    在函数调用中,call将引用从中检索属性的对象。

    B中。使用函数对象的内在applysayIt.call(lemon); 函数:

    sayIt

    表示“调用this函数,在函数调用中生成lemon = call。”如果你将其他参数传递给sayIt.call(lemon, 1, 2, 3); ,它们将被传递给函数,所以:

    sayIt

    表示“使用this = lemon致电1并传入23apply

    还有// note ------------v-------v---- the square brackets create an array sayIt.applyl(lemon, [1, 2, 3]); // More explicitly: var a = [1, 2, 3]; sayIt.apply(lemon, a); 函数,除了将参数作为数组而不是单独传递之外,这是一回事:

    sayIt

    表示“使用this = lemon致电1并传入23和{{1}}。

    < / LI>

    我在博客上写了一些关于这些主题的内容,FWIW:

    更多探索:

答案 1 :(得分:3)

我假设第一个例子中有拼写错误,你打算写alert(lemon.thought())。您看到undefined undefined的原因是因为this.thought设置为sayIt函数的返回值。在sayIt函数中,this引用window对象而不是Fruit对象。由于window没有tastetype属性,因此您会看到undefined undefined

在第二个例子中(我再次假设你有一个拼写错误而你打算做alert(lemon.thought())),你this.thought被设置为对sayIt函数的引用,所以你实际上并没有打电话给它。当您提醒某个功能的引用时,它将打印出该功能的来源。

<强>奖金

如果你这样做,你可以按照你想要的方式工作:

this.thought = sayIt.call(this);

这会将this设置为指向Fruit对象,现在sayIt将返回您想要的内容。

在第二个例子中,如果你这样做,你将得到你想要的东西:

alert(lemon.thought());

lemon.thought引用sayItthis将被正确设置,因为您正在调用lemon的成员函数。

call(或其朋友apply)的第一个参数是该函数上下文中this的值。

<强>更新

Dan,在第二个例子中,即使没有我做出的改变,也就是说,如果你仍然有lemon.thought = sayIt;而你说alert(lemon.thought);。您仍将获得该函数的源代码,因为您没有调用该函数并将其结果传递给alert。您将函数引用本身传递给alert,因此它将打印源。

答案 2 :(得分:2)

第一个代码:

编辑注意:已编辑以反映问题中的修改

function Fruit(type){
    this.type = type;
    this.taste = "Awful";
    this.thought = sayIt(); // this line invokes sayIt, with global context,
                            // so sets thought to 'undefined undefined'
}

function sayIt() {
    return this.taste+" "+ this.type; // as called, this == window, not the Fruit object
}

window.onload = function() {
    var lemon= new Fruit("Lemon");
    alert(lemon.thought);    // see above
};

第二段代码:

function Fruit (type){
    this.type = type;
    this.taste = "Awful";
    this.thought = sayIt;
}

function sayIt(){
    return this.taste +" "+ this.type;
}

window.onload = function (){
    var lemon= new Fruit("Lemon");
    alert(lemon.thought);  // doesn't -call- the function, results in .toString() on
                           // the function object
};

答案 3 :(得分:1)

我认为你在第一个例子中有一个错误。您写了alert(lemon.sayIt);,其中应该是alert(lemon.thought);。总之...

  

在调用sayIt函数时使用括号。这会提醒“undefined undefined”,为什么?

因为当您执行this.thought = sayIt();时,您要将sayIt返回值分配给this.thought。当您调用sayIt()时,函数内的this将引用window为浏览器的全局对象。 window.tastewindow.type未定义。因此,this.thought将为其分配字符串"undefined undefined"

  

sayIt函数没有括号。这将在警报框中写下函数,为什么?

在这种情况下,您要将对函数本身的引用分配给this.tought。函数的字符串表示形式是代码本身。现在,您可以通过lemon.tought()调用该函数。如果您这样做,this将引用lemon对象,输出将按预期进行。

所以,调用函数:alert(lemon.tought())

我建议你阅读

答案 4 :(得分:0)

根据您的代码,“lemon”对象具有“type”,“taste”和“thought”属性。

alert(lemon.sayIt);

此行警告“lemon”上的“sayIt”属性的值,转换为String。由于“lemon”对象没有“sayIt”属性,因此它将值 undefined 转换为字符串并显示它。

alert(lemon.thought);

此行警告“lemon”上的“思想”属性的值,转换为字符串。由于“思想”属性是一个函数,字符串转换显示函数的文本。

您可能想要做的是调用该函数,并显示其返回值:     警报(lemon.thought());

答案 5 :(得分:0)

  1. 函数sayIt在调用后定义。将sayIt的定义移到水果定义之上将会解决。

  2. 您正在警告函数的定义,而不是调用该函数的返回值。

答案 6 :(得分:0)

sayIt不是Fruit对象的函数 - 它是window对象的函数。

Fruit.thought是一个函数,或者是指向window.sayIt函数的“函数指针”。