简体   繁体   English

Javascript 对象如何工作?

[英]How do Javascript objects work?

Preface前言

  1. I know the right code for these examples.我知道这些示例的正确代码。
  2. What I want to know is why the following examples won't work as expected.我想知道的是为什么以下示例无法按预期工作。

Code代码

  • With parentheses when calling sayIt function.调用sayIt function 时带括号。

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

    This will alert "undefined undefined", why?这会提示“未定义未定义”,为什么?

  • sayIt function without parentheses. 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); };

    This will literally write down the function on the alert box, why?这实际上会在警告框中写下 function,为什么?

Thank you in advance.先感谢您。

Notes inline, discussion below, references and further reading at the end:内联注释,下面的讨论,最后的参考和进一步阅读:

  • With parentheses when calling sayIt function.调用sayIt function 时带括号。

     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 without parentheses. 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); };

Key concepts from the above:上述关键概念:

  1. Functions are objects.函数是对象。 You call a function by using a reference to it followed by () , eg:您通过使用对它的引用后跟()调用function ,例如:

     x = foo();

    means "call foo and assign its return value to x ".表示“调用foo并将其返回值分配给x ”。

    You refer to the function object by just using its name, sans () , eg:您只需使用其名称sans ()即可引用function object ,例如:

     x = foo;

    means "assign the function object foo to x . (You could then call it: x() .)表示“将 function object foo分配给x 。(然后你可以称之为: x() 。)

  2. Unlike some other languages, in JavaScript, this is defined entirely by how a function is called , not where it's defined .与其他一些语言不同,在 JavaScript 中, this完全由function 的调用方式定义,而不是定义在哪里 When you call a function via a free variable (eg, foo() ), you're doing nothing to explicitly set the this for the function call, and so this will be the default value, which is the global object ( window on browsers). When you call a function via a free variable (eg, foo() ), you're doing nothing to explicitly set the this for the function call, and so this will be the default value, which is the global object ( window on browsers )。

    You can set what this is in two different ways:您可以通过两种不同的方式设置this是什么:

    A. Put the function reference on an object property and call the function via the property's reference to it, eg: A. 将 function 引用放在 object 属性上,并通过属性对它的引用调用 function,例如:

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

    You'd then call it via the property:然后你可以通过属性调用它:

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

    Within the function call, this will refer to the object from which you retrieved the property.在 function 调用中, this将引用您从中检索属性的 object。

    B. Using the function object's intrinsic call or apply functions: B. 使用 function 对象的内部callapply函数:

     sayIt.call(lemon);

    means "call the sayIt function, making this = lemon within the function call."意思是“在 function 调用中调用sayIt function,使this = lemon 。” If you pass further arguments to call , they'll be passed to the function, so:如果您将进一步的 arguments 传递给call ,它们将被传递给 function,因此:

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

    means "call sayIt with this = lemon and pass in 1 , 2 , and 3 .意思是“用this = lemon调用sayIt并传入123

    There's also the apply function, which is just the same thing except you pass the arguments as an array rather than individually:还有apply function,除了您将 arguments 作为数组而不是单独传递之外,这是一样的:

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

    means "call sayIt with this = lemon and pass in 1 , 2 , and 3 .意思是“用this = lemon调用sayIt并传入123

I've blogged a bit on these subjects, FWIW:我写了一些关于这些主题的博客,FWIW:

More to explore:更多探索:

I'm assuming there is a typo in the first example and you meant to write alert(lemon.thought()) .我假设第一个示例中有错字,您打算编写alert(lemon.thought()) The reason you're seeing undefined undefined is because this.thought is set to the return value of the sayIt function.您看到undefined undefined的原因是this.thought设置为sayIt function 的返回值。 In the sayIt function, this refers to the window object and not the Fruit object.sayIt function 中, this是指window object 而不是Fruit ZA8CFDE6331BD54B66AC96F8911C。 Since window doesn't have a taste or type property, you will see undefined undefined .由于window没有tastetype属性,您将看到undefined undefined

In the second example (I'll again assume you have a typo and you meant to do alert(lemon.thought()) ), you this.thought is set to be a reference to the sayIt function, so you're not actually calling it.在第二个示例中(我将再次假设您有错字并且您打算执行alert(lemon.thought()) ),您this.thought设置为对sayIt function 的引用,所以您实际上并不是调用它。 When you alert a reference to a function, it will print out the source of that function.当您警告对 function 的引用时,它将打印出该 function 的来源。

BONUS奖金

You can get it to work the way you want if you do this:如果你这样做,你可以让它以你想要的方式工作:

this.thought = sayIt.call(this);

This will set the this to point to the Fruit object and now sayIt will return what you want.这会将this设置为指向Fruit sayIt现在说它将返回您想要的。

In the second example, you will get what you want if you do this:在第二个例子中,如果你这样做,你会得到你想要的:

alert(lemon.thought());

lemon.thought refers to sayIt and the this will be set properly because you are calling a member function of lemon . lemon.thought指的是sayIt并且this将被正确设置,因为您正在调用lemon的成员 function 。

The first argument to call (or its friend apply ) is for the value of this in the context of that function. call (或其朋友apply )的第一个参数是在 function 的上下文中this的值。

UPDATE更新

Dan, in the second example even without the change I made, that is if you still have lemon.thought = sayIt;丹,在第二个例子中,即使没有我所做的改变,也就是说,如果你还有lemon.thought = sayIt; and you say alert(lemon.thought);你说alert(lemon.thought); . . You will still get the source of the function because you're not calling the function and passing its result to alert .您仍将获得 function 的来源,因为您没有调用 function 并将其结果传递给alert You're passing the function reference itself to alert , and so it will print the source.您将 function 引用本身传递给alert ,因此它将打印源代码。

First code:第一个代码:

EDIT NB: edited to reflect edits in the question编辑注意:编辑以反映问题中的编辑

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

Second code:第二个代码:

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

I think you have a mistake in the first example.我认为你在第一个例子中有一个错误。 You wrote alert(lemon.sayIt);你写了alert(lemon.sayIt); where it should be alert(lemon.thought);应该在哪里保持alert(lemon.thought); . . Anyway...反正...

With parentheses when calling sayIt function.调用sayIt function 时带括号。 This will alert "undefined undefined", why?这会提示“未定义未定义”,为什么?

Because when you execute this.thought = sayIt();因为当你执行this.thought = sayIt(); , you are assigning the return value of sayIt to this.thought . ,您将sayIt返回值分配给this.thought When you call sayIt() , then this inside the function will refer to the global object which is window is browser.当您调用sayIt()时, function 中的this将引用全局 object ,即window是浏览器。 And window.taste and window.type are not defined.并且window.tastewindow.type没有定义。 Hence this.thought will have string "undefined undefined" assigned to it.因此this.thought将分配给它的字符串"undefined undefined"

sayIt function without parentheses. sayIt不带括号。 This will literally write down the function on the alert box, why?这实际上会在警告框中写下 function,为什么?

In this case you are assigning a reference to the function itself to this.tought .在这种情况下,您将对 function 本身的引用分配给this.tought The string representation of a function is the code itself. function 的字符串表示是代码本身。 Now you can call the function via lemon.tought() .现在您可以通过lemon.tought()调用 function 。 If you do so, this will refer to the lemon object and the output will be as expected.如果这样做, this将指的是lemon object 和 output 将如预期的那样。

So, call the function: alert(lemon.tought()) .所以,调用 function: alert(lemon.tought())

I suggest you read about我建议你阅读

Based on your code, the "lemon" object has the properties "type", "taste", and "thought".根据您的代码,“柠檬” object 具有“类型”、“味道”和“思想”属性。

alert(lemon.sayIt);

This line alerts the value of the "sayIt" property on "lemon", converted to a String.此行警告“lemon”上的“sayIt”属性值,转换为字符串。 Since the "lemon" object doesn't have a "sayIt" property, it converts the value undefined to a string and displays it.由于 "lemon" object 没有 "sayIt" 属性,它将undefined的值转换为字符串并显示出来。

alert(lemon.thought);

This line alerts the value of the "thought" property on "lemon", converted to a String.此行警告“lemon”上的“thought”属性的值,转换为字符串。 Since the "thought" property is a function, the string conversion displays the text of the function.由于“thought”属性是 function,因此字符串转换显示 function 的文本。

What you probably want to do is call the function, and display its return value: alert(lemon.thought());您可能想要做的是调用 function,并显示其返回值:alert(lemon.thought());

  1. The function sayIt is defined after it is called. function 说它是在调用后定义的。 Moving the definition of sayIt above the definition of fruit would fix.将 sayIt 的定义移到fruit 的定义之上可以解决问题。

  2. You're alerting the definition of a function and not the return value from calling that function.您正在提醒 function 的定义,而不是调用 function 的返回值。

sayIt is not a function of the Fruit object - it's a function of the window object. sayIt is not a function of the Fruit object - it's a function of the window object.

Fruit.thought is a function, or a "function pointer" as it is assigned to the window.sayIt function. Fruit.thought 是 function 或“函数指针”,因为它被分配给 window.sayIt function。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM