Javascript对象如何工作

How do Javascript objects work?

本文关键字:工作 何工作 对象 Javascript      更新时间:2023-09-26

前言

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

法典

  • 调用函数时带括号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);
    };
    

    这将提醒"未定义未定义",为什么?

  • 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);
    };
    

    这将从字面上写下警报框上的功能,为什么?

提前谢谢你。

内联注释,下面的讨论,参考文献和进一步阅读:

  • 调用函数时带有括号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"。

    您只需使用函数对象的名称来引用函数对象,无需(),例如:

    x = foo;
    

    表示"将函数对象foo分配给x。(然后你可以称之为:x()

  2. 与其他一些语言不同,在JavaScript中,this完全由函数的调用方式定义,而不是定义函数的位置。当你通过自由变量(例如,foo()(调用函数时,你没有做任何事情来显式设置函数调用的this,因此this将是默认值,即全局对象(浏览器上window(。

    您可以通过两种不同的方式设置this

    A. 将函数引用放在对象属性上,并通过属性对它的引用调用函数,例如:

    // 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;
    

    然后,您将通过属性调用它:

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

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

    B. 使用函数对象的固有callapply函数:

    sayIt.call(lemon);
    

    表示"调用sayIt函数,使this = 函数调用中的lemon"。如果将进一步的参数传递给 call ,它们将被传递给函数,因此:

    sayIt.call(lemon, 1, 2, 3);
    

    表示"使用 this = lemon 调用sayIt并传入123

    还有 apply 函数,它只是将参数作为数组传递而不是单独传递:

    // 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);
    

    表示"使用 this = lemon 调用sayIt并传入 123

我已经写了一些关于这些主题的博客,FWIW:

  • 神话般的方法
  • 你必须记住this
  • 匿名匿名(更多地讨论函数引用和分配它们(

更多探索:

  • ECMAScript 规范(是的,真的(
  • MDC 的 JavaScript 页面
  • Crockford的JavaScript页面(高级,首先阅读并理解以上所有内容(

我假设第一个示例中有拼写错误,您打算写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,因此它将打印源代码。

第一个代码:

编辑

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

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
};

我认为您在第一个例子中有一个错误。你写了alert(lemon.sayIt);它应该alert(lemon.thought);的地方.无论如何。。。

调用函数时带括号sayIt。这将提醒"未定义未定义",为什么?

因为当你执行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())

我建议你阅读

  • 功能
  • 使用对象

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

alert(lemon.sayIt);

此行提醒"lemon"上的"sayIt"属性的值,转换为字符串。由于"lemon"对象没有"sayIt"属性,因此它将未定义的值转换为字符串并显示它。

alert(lemon.thought);

此行提醒 "lemon" 上的 "thought" 属性的值,转换为字符串。由于 "thought" 属性是一个函数,因此字符串转换显示函数的文本。

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

  1. 函数 say它是在调用它之后定义的。 将sayIt的定义移到水果的定义之上就可以解决了问题。

  2. 你正在提醒函数的定义,而不是调用该函数的返回值。

说它不是 Fruit 对象的函数 - 它是窗口对象的函数。

Fruit.thought是一个函数,或者是一个"函数指针",因为它被分配给window.sayIt函数。