Javascript范围和闭包问题 [英] Javascript scoping and closure problem

查看:87
本文介绍了Javascript范围和闭包问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  var calculateBonus = function() {
    alert(this);
    return (this.salary + 1000);
  }
  calculateBonus();
}

var testObj = new Employee();





在这段代码中,当我们使用new Employee()创建Employee对象时,calculateBonus函数是在创建对象时执行。当执行calculateBonus时,我们提醒此参考,警报的输出给出窗口参考。所以calculateBonus函数中的this.salary将工资绑定到window对象。



为什么在上下文中执行calculateBonus函数Windows而不是员工的背景



我尝试了什么:



我想弄清楚如何解决此问题的范围问题。请帮助我理解这个概念。



In this code when we create an object of "Employee" using "new Employee()", "calculateBonus" function is executed while creating the object. When "calculateBonus" is executed, we alert the reference of this, the output of the alert gives a "Window" reference. So "this.salary" in "calculateBonus" function binds salary to window object.

Why the "calculateBonus" function executed under the context of "Windows" and not in context of "Employee"

What I have tried:

I am trying to figure out how to resolve the scope problem for this issue. Please help me in understanding the concept.

推荐答案

在Javascript中, this 是一个棘手的概念。许多文章都是为了解释这些并发症而编写的 - 例如:

In Javascript, "this" is a tricky concept. Many articles have been written trying to explain the complications - for example:
  • this - JavaScript | MDN[^]
  • Javascript - The this keyword[^]
  • Understand JavaScript’s "this" With Clarity, and Master It | JavaScript is Sexy[^]
function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  
  var calculateBonus = function() {
    alert(this);
    return (this.salary + 1000);
  };
  
  calculateBonus.call(this);
}



注意: calculateBonus 函数不会更新Employee对象以及函数返回的值不会在任何地方使用。您可能想要修复它。


NB: The calculateBonus function doesn't update the Employee object, and the value returned from the function isn't used anywhere. You'll probably want to fix that.


请参阅我对解决方案的评论1.除此之外,我想说:



从OOP想法中清除头脑非常重要。这就是本文所谓的干扰: JS Objects:Distractions



我认真地建议学习和理解。



至于你的例子,我认真建议你使用严格模式的。它会迅速从一些干扰中清除你的思绪。请参阅:严格模式 - JavaScript | MDN



它有一件重要的事情: alert(this)将显示未定义。这是对可怕的非严格执行的非常重要的改进,它会立即为您提供所需的食物。



-SA
Please see my comment to the Solution 1. In addition to that, I want to say:

It's really important to clear the mind from OOP ideas. This is what is called "distractions" in this article: JS Objects: Distractions.

I seriously advise to learn and and understand well.

As to your example, I seriously advise you to use strict mode. It will quickly clean up your mind from some of the "distractions". Please see: Strict mode — JavaScript | MDN.

One important thing it does: alert(this) will show undefined. This is very important improvement over the dreaded non-strict execution which would immediately give you the required food for thought.

—SA


我希望你喜欢我在解决方案2中提供的链接。现在,让我们看看你的简单案例发生了什么。其中一个可能的解决方案是:



I hope you enjoyed the link I provided in Solution 2. Now, let's see what's going on with your simple case. One of the possible solutions would be this:

function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  // make alculateBonus a property:
  this.calculateBonus = function() {
    alert(this.name); // "Mayank"
    return (this.salary + 1000);
  }
  this.calculateBonus();
}



假设您在所有情况下都使用严格模式。在开发过程中使用非严格行为太混乱了。在原始代码中, alert 会显示窗口对象,这是完全错误的(或者,那些过时的错误决定! )并且很难识别那是什么。我输出 this.name 只是为了显示一些证据证明这是正确的这个。 (根据Miln's Winnie-the-Pooh的兔子的说法:'这个'可以是不同的!。:-))



当然,在这段特殊的代码中,使 calculateBonus 完全不切实际,因为这不是你想要做的;您可能不希望将此函数公开给对象用户。我非常确定你知道实际的解决方案;只有揭开这个的神秘感才有用。所以,以防万一:


Let's assume you are using strict mode in all cases. Non-strict behavior is too confusing to use during development. In your original code, alert would show the window object, which is plain wrong (or, those obsolete wrong decisions!) and hard to recognize what is that. I output this.name only to show some evidence that this is correct "this". (In the style of the sayings by Rabbit from Miln's Winnie-the-Pooh: "'this' can be different!". :-))

Of course, in this particular piece of code, making calculateBonus would be utterly impractical, because this is not what you meant to do; you probably did not want to expose this function to the object users. I'm pretty much sure that you knew the practical solution; only it would be not useful to uncover the "mystery" of "this". So, just in case:

function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  calculateBonus = function(owner) { // not a property!
    alert(owner.name);
    return (owner.salary + 1000);
  }
  calculateBonus(this);
}



现在,让我们说,你想要使用闭包。大!这实际上比使用属性好得多。我希望解决方案显而易见:


Now, let's say, you want to use the closure. Great! This is actually much better idea than using properties. I hope the solution would be obvious:

function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  var name = this.name;
  var salary = this.salary;
  var calculateBonus = function() { // use closure
    alert(name);
    return (salary + 1000);
  }
  calculateBonus();
}



让我们迈出新的一步。为什么我们需要calculateBonus呢?摆脱它:


Let's make another step. Why would we need "calculateBonus" at all. Get rid of it:

function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  var name = this.name;
  var salary = this.salary;
  (function() { // use closure
    alert(name);
    return (salary + 1000);
  })();
}



好​​多了,不是吗?请参阅 Pluralitas non est ponenda正弦必需 ,另请参阅:

奥卡姆剃刀 - 维基百科,免费百科全书

立即调用的函数表达式 - 维基百科,免费的百科全书



结合上述内容的另一种变体:


Much better, isn't it? Please see Pluralitas non est ponenda sine necessitate, see also:
Occam's razor — Wikipedia, the free encyclopedia,
Immediately-invoked function expression — Wikipedia, the free encyclopedia.

Another variant combining some of the above:

function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  var owner = this;
  (function() { // use closure
    alert(owner.name);
    return (owner.salary + 1000);
  })();
}








现在,我想介绍另一个令人兴奋的严格功能模式。它可以通过消除使用构造函数的虚假自由来帮助您。试试这个:





Now, I want to introduce another exciting feature of strict mode. It can help you by taking out false freedom of using the constructors. Try this:

function ConstructorInFact() {
	this.A = 13;
	return 14;
}

var a = new ConstructorInFact();
var b = ConstructorInFact();



我希望你能看到这段代码是怎样的愚蠢。如果将其用作构造函数( a ),则不使用返回14 。如果它不是构造函数调用( b ),则this是没有意义的。但是,所有这些都将在非严格模式下工作。有人说它很好,但它不会检测到这段代码的愚蠢。切换到严格模式,并在第一次尝试时注释掉最后一行( b )。仍然,它会工作。



取消注释最后一行。在想要的行中,将检测到问题。惊喜:在this.A = ......行中:这是未定义的。请注意,问题仅在最后一行存在时才存在。



等一下! JavaScript不是解释器吗?不,它不是一个纯粹的翻译。该脚本首先进行词法分析。另一个惊喜? :-)



-SA


I hope that you can see how this code is silly. If this is used as a constructor (a), return 14 is not used. If it is as not a constructor call (b), "this" is pointless. However, all this will work in non-strict mode. Some say it's nice, but it won't detect the silliness of this code. Switch to the strict mode and, for a first attempt, comment out the last line (b). Still, it will work.

Uncomment the last line. In want line the problem will be detected. Surprise: in the line "this.A =…": "this is undefined". Note that the problem only exists if the last line is there.

Wait a minute! Isn't JavaScript an interpreter? No, it is not a pure interpreter. The script is first lexically analyzed. Another surprise? :-)

—SA


这篇关于Javascript范围和闭包问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆