【问题标题】:Javascript - get a variable from inside the local scope of a functionJavascript - 从函数的本地范围内获取变量
【发布时间】:2009-10-29 14:50:57
【问题描述】:

除了基本的 javascript,我对任何东西都不擅长,所以请原谅这个简单的问题。

我正在使用jsDraw2D 库。这个库有一个图形对象,如下所示:

function jsGraphics(canvasDivElement) {
  var canvasDiv;
  this.drawLine = drawLine;
  function drawLine(point1, point2) {
    // do things with canvasDiv
  }
}

你可以这样使用它:

var gr = new jsGraphics(document.getElementById('canvas'))
gr.drawLine(new jsPoint(0,0), new jsPoint(10,10))

我想在 jsGraphics 中添加一个函数,以便我可以调用

gr.getCanvasElement()

有没有办法在不编辑库本身的情况下做到这一点?

我试过了

jsGraphics.prototype.getCanvasElement = function() { return canvasDiv }

但这似乎不起作用。我有一种直观的感觉,它与那个新关键字有关,但如果你能解释为什么它确实没有用,那也会有帮助。

【问题讨论】:

  • 您是否就这样将document.getElementById('canvas') 传递给jsGraphics?如果你是,你可以打电话给document.getElementById('canvas') 得到同样的东西canvasDiv 持有。
  • 嗯,我想要的并不是真正的 canvasDiv,而是它的宽度/高度,它将用于我计划添加的一些简化外观方法中。然而,页面本身将有许多 jsGraphics 对象,我需要依次处理每个对象。

标签: javascript


【解决方案1】:

不,这不是使用普通的基于 JavaScript 原型的继承,而是为 jsGraphics 的每个实例添加一个单独的 drawLine 函数,每个实例都有一个围绕其自己的 canvasDiv 变量的闭包。

一旦function jsGraphics() { 关闭},就根本无法访问canvasDiv 变量,除非里面的函数之一提供了对它的访问。这通常是故意进行的,以创建私有变量,明确阻止您访问 canvasDiv。

【讨论】:

  • 真的吗?我认为在 javascript 中几乎任何事情都是可能的......从技术上讲,我想将它视为一个受保护的变量,从一些方法中使用,如果这使它更容易,我将在未来添加。
  • 是的,我更喜欢调试友好的 Python 方法,您可以将其设置为 this._canvasDiv 并且任何使用以下划线开头的变量的人都将受到困扰,除非他们是成员函数(或他们真的知道他们在做什么)。不过,这需要您更改构造函数。
【解决方案2】:

您不能只访问 canvasDiv 元素,因为如果它从未使用 this 关键字分配给构造函数中的对象,则对该对象的引用存在于构造函数本身创建的闭包中。

但是,您可以将构造函数包装在一个新的构造函数中,然后将原型设置为相等:

function myJsGraphics(canvasDivElement) {
  this.canvasDiv = canvasDivElement;
  jsGraphics.call(this, cavasDivElement);
}

myJsGraphics.prototype = jsGraphics.prototype;

现在您应该可以使用新的构造函数访问元素了:

var obj = new myJsGraphics(document.getElementById('blah-elem'));
elem = obj.canvasDiv;

如果你不习惯,整个闭包会有点奇怪,但要点是在某个范围内定义但在其他地方可用的函数可以始终引用定义它们的范围内的变量。最简单的例子是当你有一个返回函数的函数时:

function makeIncrementer(start) {
  return function () { return start++; };
}

var inc = makeIncrementer(0);
var inc2 = makeIncrementer(0);
inc(); // => 0
inc(); // => 1
inc(); // => 2
inc2(); // => 0

当函数从 makeIncrementer 函数返回时,对“start”变量的引用被“关闭”。不能直接访问。同样的事情发生在对象的构造函数中,局部变量被“封闭”到对象的成员函数中,它们充当私有变量。除非在构造函数中定义了对私有成员的方法或变量引用,否则您将无法访问它。

【讨论】:

  • jsGraphics.call(this);应该是 jsGraphics.call(this, canvasDivElement);
【解决方案3】:

这种“私有状态”技术在过去几年中变得越来越流行。就我个人而言,在尝试从控制台快速调试某些东西或覆盖 3rd 方库中的行为时,我发现它奇怪地受到限制。这是我认为“该死的,为什么我不能用语言做到这一点”的少数几次之一。当我真的需要快速调试“私有变量”时,我在 Firefox 2 中利用了this bug,效果很好。

我很想知道其他人何时使用此成语或何时避免使用它。 (@bobince 我在看着你)。

无论如何@bobince 已经回答了你的问题(简而言之:不,你不能从你所在的范围内访问canvasDiv 变量)。

但是,您可以做的一件事是在 hack 或编辑 3rd-party 库之间进行权衡(我总是选择 hack ;):您可以扩充对象以保存您知道需要的引用稍后。

Hack 1:如果您自己控制对象实例化:

var canvas = document.getElementById('canvas');
var gr = new jsGraphics(canvas);
gr._canvasDiv = canvas; // Augment because we'll need this later

// Sometime later...

gr._canvasDiv; // do something with the element

如果库支持一些类似于析构函数的概念(在卸载页面或其他东西时触发),请务必在此处也清空或删除您的属性,以避免 IE 中的内存泄漏:

delete gr._canvasDiv;

OR Hack 2:在包含库之后覆盖构造函数:

// run after including the library, and before
// any code that instantiates jsGraphics objects
jsGraphics = (function(fn) {
    return function(canvas) {
        this._canvasDiv = canvas;
        return fn.apply(this, arguments)
    }
}(jsGraphics))

然后以gr._canvasDiv 访问该元素(现在是公开的)。关于在页面卸载时删除它的相同说明也适用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 2015-09-30
    • 2012-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多