为什么NodeJS不像浏览器那样执行构造函数?

时间:2015-01-23 16:27:16

标签: javascript node.js browser constructor

我正在玩NodeJS,我注意到一些奇怪的事情。

我只是通过下面的代码探索构造函数的使用。

// We declare the constructor.
function Personne(inName) {
    console.log("go!");
    if ('undefined' != typeof inName) {
        this.name = inName;
    }
}

// We declare the object's prototype (that will be used by the constructor).
var PersonnePrototype = {
    name: 'toto',
    setName: function(inName) {
        this.name = inName; // "this" refers to the new object being created.
    },
    getName: function() {
        return this.name; // "this" refers to the new object being created.
    }
};

Personne.prototype = PersonnePrototype;

var p = new Personne("Tom"); 
console.log("p.getName(): " + p.getName());
console.log(p);
console.log(Object.getPrototypeOf(p));

首先,我希望在使用运算符Personne(inName)时执行构造函数new中的代码。

显然,事实并非如此。下面,我给出执行的输出。

$ node loop-closure.js 
p.getName(): toto
{ prototype: { name: false, setName: [Function], getName: [Function] } }
{ name: 'toto', setName: [Function], getName: [Function] } 

您可以看到构造函数未执行...

但是,如果我在Chrome或Firefox上执行相同的代码,则会执行构造函数!

的FireFox:

"go!"
"Given: Tom"
"p.getName(): Tom"
Object { name: "Tom" }
Object { name: "toto", setName: window.onload/PersonnePrototype.setName(inName), getName: window.onload/PersonnePrototype.getName() }

铬:

go!
Given: Tom
p.getName(): Tom
Personne {name: "Tom", setName: function, getName: function}
Object {name: "toto", setName: function, getName: function}

我认为NodeJS是Chrome使用的JavaScript解释器。如果这是正确的,那么为什么Chrome和NodeJS之间的解释会有所不同?

更新

我看到了评论,我试着说:

我只是将代码复制/粘贴到文件中并在该文件上调用NodeJs。

是的,你是对的:它按预期工作。

然后我发现导致问题的原因。

我在执行的文件中有额外的代码。在我给你的代码之后,我已经发了一个return语句。下面,我给你完整的代码:

我使用的是NodeJs版本0.10.35:

$ node -v
v0.10.35
// We declare the constructor.
function Personne(inName) {
    console.log("go!");
    if ('undefined' != typeof inName) {
        this.name = inName;
    }
}

// We declare the object's prototype (that will be used by the constructor).
var PersonnePrototype = {
    name: 'toto',
    setName: function(inName) {
        this.name = inName; // "this" refers to the new object being created.
    },
    getName: function() {
        return this.name; // "this" refers to the new object being created.
    }
};

Personne.prototype = PersonnePrototype;

var p = new Personne("Tom"); 
console.log("p.getName(): " + p.getName());
console.log(p);
console.log(Object.getPrototypeOf(p));



return;

console.log("Does the prototype has a constructor property ? " + Object.getPrototypeOf(p).hasOwnProperty('constructor'));

// Other way to say the same thing:

function Personne() {
    this.prototype = {
        name: false,
        setName: function(inName) {
            this.name = inName; // "this" refers to the new object being created.
        },
        getName: function() {
            return this.name; // "this" refers to the new object being created.
        }
    }
};

var p = new Personne(); // Object "p" has a parent. This parent has been created by the prototype (which is a function).
p.setName("Tom");
console.log("The name is " + p.getName() + " / " + this.name);
console.log("Does the prototype has a constructor property ? " + Object.getPrototypeOf(p).hasOwnProperty('constructor'));

// Ou encore :

var p = Object.create(Personne.prototype);
p.setName("Tom");
console.log("The name is " + p.getName() + " / " + this.name);

// We can see the difference between the prototype and the instanced object.
// Both are objects.
// However, as you can see, they do not present the same properties.

utils.dump(Object.getPrototypeOf(p));
Object.getPrototypeOf(p).name;
utils.dump(p);

if (Object.getPrototypeOf(p).getName() != p.getName()) {
    console.log("The prototype and the object have different properties.");
    console.log("Prototype: " + Object.getPrototypeOf(p).getName());
    console.log("Object: " + p.getName());
}

// ------------------------------------------------------------------------------------
// Heritage
// ------------------------------------------------------------------------------------

function Personne() {
    this.prototype = {
        name: false,
        setName: function(inName) {
            this.name = inName; // "this" refers to the new object being created.
        },
        getName: function() {
            return this.name; // "this" refers to the new object being created.
        }
    }
};

function student() {
    Personne.call(this);
}

我虽然返回语句后的代码没有干扰。显然,确实如此。

NodeJs在执行代码之前编译所有代码。因此,如果我稍后在代码中重新定义构造函数,那么它将修改它的第一次出现。

好的,但是:

var v = 1;
console.log("v = " + v);

var v = 2;
console.log("v = " + v);

输出:

$ node test1.js 
v = 1
v = 2

var v = 1;
console.log("v = " + v);
return;
var v = 2;
console.log("v = " + v);

输出:

$ node test1.js 
v = 1

并且(可能有引用的内容):

var v = { a: 1 };
console.log("v.a = " + v.a);
return;
var v = { a: 2 };
console.log("v.a = " + v.a);

输出:

$ node test1.js 
v.a = 1

这里没什么不寻常的......返回语句之后的代码似乎没有改变return语句之前的代码。

@Alexey Ten

感谢您的提示。

Test1.js

function Construct() { this.name = "Tom"; }
var v = new Construct();
console.log("v.name = " + v.name);
return;
function Construct() { this.name = "Joe"; }

Test2.js

var Construct = function() { this.name = "Tom"; }
var v = new Construct();
console.log("v.name = " + v.name);
return;
var Construct = function() { this.name = "Joe"; }

Test1的结果是:v.name = Joe

Test1的结果是:v.name = Tom

1 个答案:

答案 0 :(得分:0)

事实上,这篇文章不是关于NodeJs,而是关于吊装(感谢Alexey Ten)

很好的解释:

http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html

使用过C,C ++,Java,PHP,Perl,Tcl,Python或GO等语言后,我希望JavaScript在变量声明方面的行为方式相同。如果变量在使用之前未声明,则取决于语言:

  • 您最终会遇到错误。
  • 变量的值未定义。

在JavaScript中,结果取决于声明变量的方式。请注意,声明变量的方式决定了它的范围。提升意味着JavaScript将放置所有变量'如果变量的范围,则在开头声明。

var x;  // Declaration
x = 10; // Initialization: this is the first time a value is affected to the variable.  
x = 20; // Affectation.

换句话说:

(function() {
    console.log("x = " + x + " f = " + f); // => x = undefined f = undefined
    // Declaration + initialization
    var x = 1; 
    var f = function() {};
})();

相当于:

(function() {
    // Declaration
    var x, f;
    console.log("x = " + x + " f = " + f); // => x = undefined f = undefined
    // initialization
    x = 2;
    f = function() {};
})();

这不等同于:

(function() {
    try {
        console.log("x = " + x + " f = " + f);
        // initialization
        x = 2;
        f = function() {};
    } catch(e) {
        console.log("ERROR: " + e.message); // => ERROR: x is not defined (and f is not defined either).
    }
})();

然而,小心!有一些微妙的捕获:

(function() {
    try {
        console.log("x = " + x + " f = " + f);
        x = 1;
        f = function() {};
    } catch (e) {
        console.log("ERROR: " + e.message); // => ERROR: x is not defined (and f is not defined either).
    }
})();

// x and f should be defined ???
console.log("x = " + x + " f = " + f); // => ReferenceError: x is not defined.

应该定义x和f吗?实际上,定义x和f的代码没有被执行,因为之前引发了异常。如果你试试这个:

(function() { 
    try {
        x = 1;
        f = function() {};
    } catch (e) {
        console.log("ERROR: " + e.message);
    }
})();

console.log("x = " + x + " f = " + f); // => x = 1 f = function () {} 

OR:

(function() {
    try {
        console.log("x = " + x + " f = " + f); // => x = undefined f = undefined
        x = 1;
        f = function() {};
    } catch (e) {
        console.log("ERROR: " + e.message);
    }
})();

console.log("x = " + x + " f = " + f); // => x = 1 f = function () {}
var x = 10, f;