Javascript - 从函数的局部范围内获取变量

时间:2009-10-29 14:50:57

标签: javascript

除了基本的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 }

但这似乎不起作用。我有一种直觉,认为它与某个新关键字有关,但是如果你能解释为什么它不会那么有用呢。

3 个答案:

答案 0 :(得分:4)

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

关闭function jsGraphics() {}根本没有办法访问canvasDiv变量,除非其中一个函数提供对它的访问权限。这通常是故意制作私有变量,明确地阻止你进入canvasDiv。

答案 1 :(得分:3)

您不能仅仅必须访问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”变量的引用是“关闭”。它无法直接访问。同样的事情发生在一个对象的构造函数中,其中局部变量被“关闭”到对象的成员函数中,并且它们充当私有变量。除非有对构造函数中定义的私有成员的方法或变量引用,否则您无法访问它。

答案 2 :(得分:2)

这种“私人国家”技术在过去几年中变得越来越惯用。就个人而言,当我尝试从控制台快速调试某些东西或覆盖第三方库中的行为时,我发现它有点奇怪。这是我想的几次之一“该死的,我为什么不能用这种语言来做这件事”。当我真的需要快速调试“私有变量”时,我在Firefox 2中利用this bug效果很好。

我很想知道其他人何时使用这个成语或什么时候避免它。 (@bobince我在看你)。

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

但是,你可以做的一件事是在黑客攻击或编辑第三方库之间进行权衡(我总是去寻找黑客;):你可以扩充对象来保存你需要的参考资料后面。

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的形式访问元素(现在公开)。关于在页面卸载时删除它的相同说明适用。