0

使用 C/C++、Java 编程后,我发现很难理解以下程序的输出。

http://jsfiddle.net/iamrohitbanga/nubgw/

var foo = function() {}
foo.prototype.out = function() {
    console.log(this.num);
}
var bar = function() {};

var f = new foo();
f.num = 1;
var b = new bar();
b.num = 2;

console.log(this);           // 1
f.out();                     // 2
foo.prototype.out.call(b);   // 3
foo.prototype.out.call(bar); // 4

我看到以下输出

Window
1
2
undefined

我已经用 javascript 编码有一段时间了,可以理解一些概念,但对我来说并不是一切都清楚。

我有一个粗略的了解。我觉得在全局空间中 this 指向窗口,因此第一行输出很清楚。对于第二行,我认为由于函数 out 是在 f 上调用的,所以 this in out 的值是 f。对于第三个,我的感觉是,通过调用输入为 b 的函数,-this 的值被设置为 b。对于第四个 bar 是一个全局对象,它的字典中没有名为“num”的成员。

我的理解正确吗?有人可以在这个程序的上下文中解释“this”和“prototype”的作用吗?我发现原型的语法有点晦涩。当我在 gmail 窗口中按 F12 并将程序粘贴到那里时,也在 chrome 中。第三行输出未定义,不是 2。但在 jsfiddle 中是 2。这似乎有点令人毛骨悚然。为什么不一样?

4

3 回答 3

2

console.log(this)

你的假设是正确的。您的程序在浏览器中的全局范围内运行window


f.out();

我不确定原型的概念是否存在于 C/C++ 或 Java 中。本质上,对象构造函数的原型是对象可以继承的东西。将函数添加到foos 的原型使其可用于foos 的所有实例。

在这种情况下,在程序的前面,您创建了一个foo被调用的实例f。然后,将f被调用的属性设置num1

out, 一个函数可f通过扩展foo'prototype console.logsnum被调用的上下文对象的属性(在本例中为f)。

因此,f.out();打印1.


foo.prototype.out.call(b);

callFunction对象原型上的一个函数。call在第一个参数的上下文中调用函数。本质上,这一行 ( foo.prototype.out.call(b);) 与b.out();作为b上下文参数传递的操作相同。

此行输出的其余解释与最后一行的全部解释相同


foo.prototype.out.call(bar);

在最后一行中,您正在调用out. 是一个函数对象。没有属性,因此是。barbarbarnumbar.numundefined

这并不是说您不能bar像使用fand那样添加属性b。函数也是对象。因此,您可以将属性添加到与和bar完全相同的方式。添加会产生你认为它会产生的结果。或者至少我希望你认为它会......fbbar.num = 3

于 2012-09-23T05:11:54.543 回答
1

this表示代码执行的范围。在您的情况下,它是全局范围window

JavaScript 中的原型只是一个具有属性和方法的对象。您可以向它添加成员,也可以从它继承。您可以阅读这篇文章以获取更多信息。

让我们分解您的代码,一一查看。

  1. f.out();

    这也指的是以下对象

    var f = new foo();
    f.num = 1; //Here you define a property `num` as 1
    

    然后,当您调用f.out()原型函数时,将简单地记录num

  2. foo.prototype.out.call(b);

    在这里,您可以直接访问该函数并将一个对象传递给该函数。因此,当执行该方法时,它this代表的是传递的对象,因此最终记录了它的值。

  3. foo.prototype.out.call(bar);

    在这部分,对象 bar 是一个空对象var bar = function() {};,因此函数无法读取其num属性,因此输出为undefined

于 2012-09-23T05:02:42.140 回答
1

this 指的是当前范围。

话虽如此,一步一步这就是为什么你得到你得到的结果

var foo = function() {}
foo.prototype.out = function() {//f.out inherits this and so prints 1
    console.log(this.num);
}
var bar = function() {};

var f = new foo();
f.num = 1;
var b = new bar();
b.num = 2;

console.log(this);           
 /* At this point you are making the above log call, outside of any local scope.
 in the global scope =this= refers to =window= */

f.out();
 /* In here the keyword =this= refers to the object =f=
 If we look above it says f.num is 1, so the inherited function which outputs 
 the =num= property then outputs 1.*/


foo.prototype.out.call(b);
/*by adding the call method you are assigning the this keyword to the b object, and
since b.num is 2, just as in the previous step that is being output*/

foo.prototype.out.call(bar); // 4
/*This returns undefined because as in all previous steps, inside the =out= 
function we are printing object.num.  The bar object, however, does not have 
this value*/

我已将解释作为注释放在代码中。至于 gmail 中的奇怪行为,有可能因为这些都在全局范围内,某些东西被 gmail 中的代码覆盖了。这是一个应该防止上述情况发生的闭包。第一个日志将更改,因为它将不再引用全局范围

(function(){

   var foo = function() {}
   foo.prototype.out = function() {
       console.log(this.num);
   }
   var bar = function() {};

   var f = new foo();
   f.num = 1;
   var b = new bar();
   b.num = 2;

   console.log(this);           // 1
   f.out();                     // 2
   foo.prototype.out.call(b);   // 3
   foo.prototype.out.call(bar); // 4

})();
于 2012-09-23T05:25:22.323 回答