作为原型添加到JS对象的属性被提升,而原型函数则没有

时间:2017-03-26 13:43:44

标签: javascript variables prototype hoisting

我(或者至少我以为我)非常熟悉JavaScript中Hoisting的概念。

考虑以下陈述:

  

函数声明将与其正文一起提升,而函数表达式则不会; 只会提升var语句

     

函数声明函数变量总是被JavaScript解释器” - Berry Cherry

移动('悬挂')到JavaScript范围的顶部

现在考虑以下功能:

function User() {
    this.name = "";
    this.life = 100;
    this.heal = function heal(player) {
        player.life+=5;
        console.log("\nHey" + player.name + "! Player " + this.name + " healed you for 5.");
    } 
}

...以及以下用户:

var Dan = new User("Danny");
var Liz = new User("Lizzy");

假设我想以原型函数的形式向已定义的用户添加新的 技能 ,如此(附加到代码中):

User.prototype.uppercut = function uppercut(player) {
    player.life-=10;
    console.log("\nBaaam! " + player.name + ", player " + this.name + " uppercuted you for 10 damage.");
};

...现在,使用 技能 (在原型之前添加此功能)

Liz.uppercut(Dan);
Liz.uppercut(Dan);

...我会收到以下错误:

Liz.uppercut(Dan);
    ^
TypeError: Liz.uppercut is not a function

我应该使用原型向User对象添加属性,但是在原型声明之前在代码中访问它,它将 工作 (它被提升):

console.log("Hey there " + Dan.name + "! You have " + Dan.mana + " remaining mana.");
User.prototype.mana = 100;

基本上,我向我确认同样的 提升 原则适用于功能&变量,也适用于原型。

问题1:这个逻辑是否有效,若然,你能解释一下原因吗?

问题2:如果有一种方法可以避免在原型函数调用之上移动原型表达式吗?

谢谢并且有一个好的!

代码段



function User(name) {
    this.name = name;
    this.life = 100;
    this.heal = function heal(player) {
        player.life+=5;
        console.log("Hey" + player.name + "! Player " + this.name + " healed you for 5.");
    }
}

var Dan = new User("Danny");
var Liz = new User("Lizzy");

Liz.uppercut(Dan);
Liz.uppercut(Dan);

console.log(Liz.name + " you know have " + Liz.life + " life.");

User.prototype.mana = 100;
User.prototype.uppercut = function (player) {
    player.life-=10;
    console.log("Baaam " + player.name + "! Player " + this.name + " uppercuted you for 10 damage.");
};

console.log("Hey there " + Dan.name + "! You have " + Dan.mana + " remaining mana.");
Dan.mana = 200;
console.log("Hey there " + Dan.name + "! You have " + Dan.mana + " remaining mana.");




3 个答案:

答案 0 :(得分:0)

不,分配(原型属性或其他)不会被吊起。

代码

function User() { this.name = ""; … }
var Dan = new User("Danny");
console.log("Hey there " + Dan.name + "! You have " + Dan.mana + " remaining mana.");
User.prototype.mana = 100;

不起作用,它会记录Hey there ! You have undefined remaining mana.

答案 1 :(得分:0)

您在此处混淆变量属性。变量被悬挂,属性没有。

在您的示例中,Dan是变量,manaDan的属性。

JavaScript处理undefined变量的方式与undefined属性不同。

通过拆分声明的左侧,

变量在声明时被悬挂。即var Dan = new User("Danny");分为两个语句var Dan; Dan = new User("Danny");var Dan然后悬挂到函数的顶部。但任务仍然存在。

如果您的代码仅包含Dan = new User("Danny");,则会收到ReferenceError,因为您将尝试对未声明的变量进行赋值。声明丢失了,因此该变量从未被提升过。

另一方面,

属性的运作方式不同。属性访问器返回父对象上的哈希查找结果。在Dan.mana的情况下,定义了父对象,因此没有ReferenceError,但mana不是Dan的属性,因此散列查找返回undefined。没有发生提升,因为没有变量声明。

因此,原型不能与吊装相关联,因为它们是严格的分配操作。即使原型在功能开始时被修改,它也不会受到提升的影响,因为提升仅 会影响变量的声明,而不是分配(发生在呼叫的右侧)。

答案 2 :(得分:0)

访问未在对象上定义的属性将为您提供undefined。这里没有提升规则。

  • Liz.mana将为您提供undefined
  • Liz.uppercut也会为您提供undefined
  • Liz.agility也会为您提供undefined

调用Liz.uppercut(Dan)会引发错误,因为您尝试将Liz.uppercut作为函数调用undefined。这导致“未定义不是函数”错误。