1

我注意到 Google Chrome 调试器的行为完全不同,具体取决于 JS 对象的创建方式;

如果我创建一个这样的 js 对象;

var SonA = function(thename) {
               this.firstname = thename || "Graham";
               this.age = 31;
}

SonA.prototype = new Father();

然后 Chrome 的调试器不允许我深入查看原型。但是,它确实给了我实例变量名称和年龄的键值对。

但是,如果我省略this关键字,我可以深入到原型,但我不会在调试器中显示实例变量。

//SonB doesn't use this keyword    
var SonB = function(thename) {
                  firstname = thename || "Graham";
                  age = 31;
           } 

SonB.prototype = new Father();
console.log(new SonA()); //this logs as: SonA {firstname: "graham", age: 31}
console.log(new SonB()); //this logs as as drill down object that shows the prototype

有谁知道这里发生了什么,为什么调试器的行为不同?下面的图片和 jsfiddle 可能会使问题更清晰易懂;

截屏

http://jsfiddle.net/7z8sp/1/

4

3 回答 3

2

我看不出你想要达到什么目的。您可以“深入”到原型的唯一原因构造函数没有设置任何属性,而是创建了隐含的全局变量。只需将此行添加到您的小提琴中:sonB

console.log(age);//<--logs 31

它记录由sonB构造函数设置的值。如果你想获得原型属性,你要么:删除孩子的属性,要么使用该Object.getPrototypeOf()方法。

澄清一下:这不是调试器固有的,而是 JS 获取对象的值和属性的方式。考虑以下:

var emptyObject = {};
console.log(emptyObject.someProperty);//logs undefined
Object.prototype.someProperty = 'YaY';
console.log(emptyObject.someProperty);//logs YaY
emptyObject.someProperty = function()
{
    return Object.getPrototypeOf(this).someProperty;
};
console.log(typeof emptyObject.someProperty);//function
console.log(emptyObject.someProperty());//YaY again
delete(emptyObject.someProperty);//returns true
console.log(emptyObject.someProperty);//logs YaY.

这是什么意思:简单地说,如果您尝试访问任何对象(数组、对象、函数、批次)上的属性,JS 将首先检查该特定实例是否定义了该属性,如果没有,则 JS 步骤在原型链中上升一个级别。如果该原型没有请求的属性,则 JS 跳到下一个原型,以此类推。如果没有找到财产,undefined将被退回。
因此,如果你的构造函数设置了某些属性,JS 就不会打扰原型并尽快返回属性。

同样的逻辑适用于隐含的全局变量。如果变量缺少var关键字,JS 会扫描范围(当前函数、“父”函数,最后是全局范围)以搜索该变量。如果找到,该变量将被使用或重新分配(取决于您在代码中使用它做什么)。如果没有找到变量,那么 JS 会为您创建一个。可悲的是,没有费心回到当前范围。结果:创建了一个全局变量。
在您的代码中,Father构造函数为每个实例创建一个新的函数对象。这个函数依赖于一个闭包变量 ( sirname) 和一个全局变量 ( firstname)。后者不是由SonA,因为该构造函数分配了一个新属性。但是,SonB确实会创建两者共享的全局变量。SonASonB

getName的成员函数Father正在处理的唯一原因sonB是因为该方法也依赖于范围扫描和隐含的全局:

new SonB();//<-- constructor sets age and firstname globals
SonB.getName();//<-- ~= Father.getName.apply(SonB,arguments);
     ||
     ---> gets firstname global that was set in SonB constructor, uses that value

就这些了,只需将Father的getName方法重新定义为:

this.getName = function()
{//use this to point at calling context -> IE the instance on which the member function is being invoked
    return this.firstname + ' ' + surname;
};
于 2012-11-16T13:41:44.550 回答
1

Console.dir()改为使用:http: //jsfiddle.net/7z8sp/3/

于 2012-11-16T13:33:35.577 回答
1

使用 24.0.1312.5(官方版本 166104)测试版,我得到了这个:

SonA
    age: 31
    firstname: "Graham"
    __proto__: Father
        getName: function () {
        __proto__: Object

SonB
    __proto__: Father
        getName: function () {
        __proto__: Object

这是正确的,因为没有this你在全局对象上分配ageand (在这种情况下)。在iframe的上下文中运行:firstnamewindowresult

> firstname
"Graham"
> age
31
于 2012-11-16T13:36:37.963 回答