JS:使用“var me = this”引用对象而不是使用全局数组
下面的例子只是一个例子,我知道我不需要一个对象来在用户点击div块时显示警告框,但这只是一个简单的例子来解释编写JS代码时经常发生的情况。
在下面的示例中,我使用全局可见的对象数组来保存对每个新创建的 HelloObject 的引用,这样,单击 div 块时调用的事件就可以使用 arry 中的引用来调用HelloObject 的公共函数 hello()。
首先看一下代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Test </title>
<script type="text/javascript">
/*****************************************************
Just a cross browser append event function, don't need to understand this one to answer my question
*****************************************************/
function AppendEvent(html_element, event_name, event_function) {if(html_element) {if(html_element.attachEvent) html_element.attachEvent("on" + event_name, event_function); else if(html_element.addEventListener) html_element.addEventListener(event_name, event_function, false); }}
/******************************************************
Just a test object
******************************************************/
var helloobjs = [];
var HelloObject = function HelloObject(div_container)
{
//Adding this object in helloobjs array
var id = helloobjs.length; helloobjs[id] = this;
//Appending click event to show the hello window
AppendEvent(div_container, 'click', function()
{
helloobjs[id].hello(); //THIS WORKS!
});
/***************************************************/
this.hello = function() { alert('hello'); }
}
</script>
</head><body>
<div id="one">click me</div>
<div id="two">click me</div>
<script type="text/javascript">
var t = new HelloObject(document.getElementById('one'));
var t = new HelloObject(document.getElementById('two'));
</script>
</body></html>
为了获得相同的结果,我可以简单地用
//Appending click event to show the hello window
AppendEvent(div_container, 'click', function()
{
helloobjs[id].hello(); //THIS WORKS!
});
以下代码替换代码:
//Appending click event to show the hello window
var me = this;
AppendEvent(div_container, 'click', function()
{
me.hello(); //THIS WORKS TOO AND THE GLOBAL helloobjs ARRAY BECOMES SUPEFLOUS!
});
从而使 helloobjs 数组变得多余。
我的问题是:这第二个是吗?您认为选项会在 IE 上创建内存泄漏或奇怪的循环引用,这可能会导致浏览器变慢或崩溃???
我不知道如何解释,但来自 C/C++ 编码器的背景,以第二种方式执行听起来像是某种循环引用,可能会在某些时候破坏内存。
我还在互联网上阅读了有关 IE 闭包内存泄漏问题 http://jibbering.com/faq/ faq_notes/closures.html (我不知道它是否在 IE7 中得到修复,如果是的话,我希望它不会在 IE8 中再次出现)。
谢谢
The example below, is just an example, I know that I don't need an object to show an alert box when user clicks on div blocks, but it's just a simple example to explain a situation that frequently happens when writing JS code.
In the example below I use a globally visible array of objects to keep a reference to each new created HelloObject, in this way events called when clicking on a div block can use the reference in the arry to call the HelloObject's public function hello().
1st have a look at the code:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Test </title>
<script type="text/javascript">
/*****************************************************
Just a cross browser append event function, don't need to understand this one to answer my question
*****************************************************/
function AppendEvent(html_element, event_name, event_function) {if(html_element) {if(html_element.attachEvent) html_element.attachEvent("on" + event_name, event_function); else if(html_element.addEventListener) html_element.addEventListener(event_name, event_function, false); }}
/******************************************************
Just a test object
******************************************************/
var helloobjs = [];
var HelloObject = function HelloObject(div_container)
{
//Adding this object in helloobjs array
var id = helloobjs.length; helloobjs[id] = this;
//Appending click event to show the hello window
AppendEvent(div_container, 'click', function()
{
helloobjs[id].hello(); //THIS WORKS!
});
/***************************************************/
this.hello = function() { alert('hello'); }
}
</script>
</head><body>
<div id="one">click me</div>
<div id="two">click me</div>
<script type="text/javascript">
var t = new HelloObject(document.getElementById('one'));
var t = new HelloObject(document.getElementById('two'));
</script>
</body></html>
In order to achive the same result I could simply replace the code
//Appending click event to show the hello window
AppendEvent(div_container, 'click', function()
{
helloobjs[id].hello(); //THIS WORKS!
});
with this code:
//Appending click event to show the hello window
var me = this;
AppendEvent(div_container, 'click', function()
{
me.hello(); //THIS WORKS TOO AND THE GLOBAL helloobjs ARRAY BECOMES SUPEFLOUS!
});
thus would make the helloobjs array superflous.
My question is: does this 2nd option in your opinion create memoy leaks on IE or strange cicular references that might lead to browsers going slow or to break???
I don't know how to explain, but coming from a background as a C/C++ coder, doing in this 2nd way sounds like a some sort of circular reference that might break memory at some point.
I also read on internet about the IE closures memory leak issue http://jibbering.com/faq/faq_notes/closures.html (I don't know if it was fixed in IE7 and if yes, I hope it does not come out again in IE8).
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
旁白:
一般来说,尽量不要使用命名内联函数表达式。它通常不会给你带来任何好处,而且在 JScript (IE) 中它们存在严重的问题。使用
function HelloObject() { ... }
语句或var HelloObject= function() { ... };
匿名表达式。“创建”上造成内存泄漏?不,您现有的代码在 IE 上已经存在漏洞。
应用于单击事件的侦听器有一个闭包,保留对父函数作用域的引用。在这两个示例中,
div_container
对象都在该范围内,因此您有一个循环引用:包含本机 JS 对象和宿主对象(例如 div、DOM 节点)的混合引用循环)是导致 IE6-7 内存泄漏的原因。
要阻止这种情况发生,您可以将 click 函数定义从父级中拉出:
现在没有闭包,
div_container
不会被记住,并且不存在循环/泄漏。但是,hello
函数只是一个函数,不知道它属于哪个div_container
(除了查看event
/this
点击即可获得)。更典型的是,您确实需要记住 div,或者,如果您以客观方式做事,则需要记住
this
:(关于 function.bind。)
这当然会带回引用循环:
你真的关心这种吗refloop?也许不是。它只真正影响 IE6-7; IE6 的情况很糟糕,因为直到您退出浏览器后内存才会归还,但越来越多的人认为仍然使用 IE6 的人应该得到他们所得到的一切。
在 IE7 上,内存泄漏会不断累积,直到您离开该页面,因此,这只对运行时间非常长的页面很重要,在这些页面中,您会重复丢弃旧的 HelloObject 并绑定新的 HelloObject。 (在这种情况下,不丢弃旧值的 HelloObjects 线性数组本身也会导致内存泄漏,直到页面卸载为止。)
如果您确实关心,因为您正在为一些运行 IE6 的肮脏公司工作,并且没有-有人关闭了浏览器,然后(a)我表示哀悼,(b)是的,您确实必须实现类似于您拥有的查找对象的东西,以充当 DOM 节点和您的 Function 对象之间的解耦层用作事件侦听器。
一些框架有自己的用于事件的解耦。例如,jQuery 将事件处理函数附加到数据查找中,并通过放入每个 Element 对象中的 id 进行索引;这让它免费解耦,尽管它确实有自己的问题......
如果您使用纯 JavaScript,这里有一些示例帮助程序代码。
摆脱了所有繁琐的管道之后,您就可以说:
不,在谈论重新循环时,我们真正担心的只是内存泄漏(主要是在 IE 中)。
Aside:
In general try not to use named inline function expressions. It doesn't usually get you anything and there are serious problems with them in JScript (IE). Either use a
function HelloObject() { ... }
statement, or avar HelloObject= function() { ... };
anonymous expression.‘Create’? No, your existing code already had leaks on IE.
The listener you applied to the click event has a closure, keeping a reference to the parent function scope. In both examples, the
div_container
object is in that scope, so you've got a circular reference:A reference loop containing a mixture of native JS objects and host objects (such as the div, a DOM Node) is what causes the memory leaks in IE6-7.
To stop this happening, you can pull the click function definition out of the parent:
Now there is no closure, the
div_container
is not remembered, and there is no loop/leak. However, thehello
function is just a function, with no idea to whichdiv_container
it belongs (other than by looking at theevent
/this
it gets on click).More typically you do need to remember the div, or, if you're doing things in an objecty way, the
this
:(About function.bind.)
Which of course brings back the reference loop:
Do you really care about this kind of refloop? Maybe not. It only really affects IE6-7; it's bad in IE6 as the memory isn't given back until you quit the browser, but then there's a growing school of thought that says anyone still using IE6 deserves everything they get.
On IE7, the memory leaks pile up until you leave the page, so it only matters for very long-running pages where you're throwing away old HelloObjects and binding new ones repeatedly. (In that case, a linear Array of HelloObjects that doesn't discard old values would also be a memory leak until page unload, in itself.)
If you do care, because you're working for some dingy corporate that runs IE6 and no-one ever closes their browsers, then (a) my condolences, and (b) yes, you will indeed have to implement something like the lookup object you had, to act as a decoupling layer between the DOM Nodes and the Function object you're using as an event listener.
Some frameworks have their own decoupling used for events. For example, jQuery attaches the event handler functions to a data lookup, indexed by an id that it drops into each Element object; this gives it decoupling for free, though it does have problems of its own...
If you're using plain JavaScript, here's some example helper code.
With all that tedious plumbing out of the way, you can then just say:
No, it's only really memory leaks (and then mostly in IE) that we're worried about when talking about refloops.
答案就在问题正文中。由于您的 C++ 背景,这对您来说似乎很奇怪。第二个选项是类似 Javascript 的方式。
The answer is in the body of the question. It seems weird to you because of your C++ background. The 2nd option is the Javascript-ish way of doing it.