Ошибка цикла JavaScript с переменной областью - PullRequest
3 голосов
/ 17 июня 2011

Итак, у меня есть этот цикл jQuery .each, и по большей части он работает как задумано; есть одна проблема, но сначала цикл:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.1.min.js"></script>
        <script type="text/javascript">
            function Pushpin(){}
            Pushpin.prototype.XZX = {
                site: null,
                getHtmlDescription: function () {
                    var html  = '<b id="infoboxTitle" style="position:absolute; top:10px; left:10px; width:220px;">' + this.site.Name + '</b>';
                        html += '<a id="infoboxDescription" style="position:absolute; top:30px; left:10px; width:220px; height:120px;">{0}</a>';

                    var description = 'Headcount: ' + this.site.Headcount + '<br />';
                    description += 'Leases: ' + this.site.LeaseCount + '<br />';

                    html = html.replace('{0}', description);

                    return html;
                }
            };

            var data = [
                    {"Address":{"City":"Atlanta","Country":"USA","County":"","Latitude":33.9882404987503,"Longitude":-84.1629638209203,"Region":"Southeast","State":"GA","StreetAddress":"Atlanta 177","ZipCode":"30096"},"Headcount":0,"ImageBytes":null,"ImageRefPath":"","LeaseCount":1,"Leases":null,"Name":"Atlanta","NextExpire":"\/Date(1495083600000-0500)\/","Number":"1052","PrimaryUse":"Garage","PropertyID":"OMNI","RecID":32839,"RecordID":1004,"RentableSquareFootage":22000,"SiteRecordID":"DEMO_29626","SiteTotalDollars":0,"Status":null,"Type":"LSE"},
                    {"Address":{"City":"Bellevue","Country":"USA","County":"","Latitude":47.6043250620083,"Longitude":-122.14236047437,"Region":"Northwest","State":"WA","StreetAddress":"Seattle 51","ZipCode":"98007"},"Headcount":0,"ImageBytes":null,"ImageRefPath":"","LeaseCount":1,"Leases":null,"Name":"Bellevue","NextExpire":"\/Date(1260424800000-0600)\/","Number":"1078","PrimaryUse":"Tower","PropertyID":"OMNI","RecID":32865,"RecordID":1027,"RentableSquareFootage":7652,"SiteRecordID":"DEMO_275651","SiteTotalDollars":0,"Status":null,"Type":"LSE"}
                ]; 

            var mylist = []; 
             $.each(data, function (i, item) { 
                try {
                    var pin = new Pushpin();  
                    pin.XZX.site = item;
                    mylist.push(pin); 
                } catch (e) { alert (e); } 
             });
            $(document).ready(function() {
                $('#btnAlert').click(function () { 
                    $('#content').html(mylist[$('#index').val()].XZX.getHtmlDescription());
                } );
            });
        </script>
    </head>
    <body >
        <div style="margin-left:auto; margin-right:auto; width:300px;">
            <div style="position:relative; width:250px;">
                <select id="index">
                    <option>0</option>
                    <option>1</option>
                </select> 

                <input type="submit" id="btnAlert"/>
            </div>
            <div id="content" style="position:relative;width:250px;"></div>
        </div>
    </body>
</html>

Также доступно на jsfiddle: http://jsfiddle.net/M8YS2/

В конце цикла, mylist[x].site для любого x все указывают на один и тот же экземпляр моего элемента данных, как я могу обойти это?

Ответы [ 4 ]

4 голосов
/ 17 июня 2011

Проблема в том, что каждый pin.XYZ является одним и тем же объектом, а именно Pushpin.prototype.XYZ.

Простое «исправление» заключается в использовании:

var pin = new Pushpin(...)
pin.XYZ = {
   site: item
   // the following will get tedious fast, consider one of the "property copy"
   // implementations floating about -- including jQuery.extend   
   getHtmlDescription: Pushpin.prototype.XYZ.getHtmlDescription
}

, который назначит новый объект для свойства XYZ каждого нового объекта Pushpin.Конечно, это также может быть сконструировано по-другому:)

По крайней мере, отодвиньте XYZ от объекта Pushpin.prototype - это позволит ему красиво обрабатываться как объект (способ, которым *Факт 1018 * фактически делает невозможным для функции, свисающей с объекта прототипа, доступ к данным экземпляра объекта, к которому применяется прототип);конечный код может выглядеть примерно так:

// We .. "wrap" the real Pushpin constructor
// somewhere global after Bing Mapi JS loaded
Pushpin = (function (bingPushpin) {
   return function Pushpin (...) {
       var pin = new bingPushpin(...)
       pin.XYZ = new XYZ()
       // trick of "returning" from ctor
       return pin
   }
})(PushPin)
// ...
var pin = new Pushpin(...)
pin.XYZ.site = item

Удачное кодирование.


Ответ перед обновлением:

На самом деле это не проблема области видимости -- не было создано непреднамеренных замыканий, и каждое выражение строго оценено.

Я подозреваю, что есть другая проблема, такая как неожиданный ввод (данные содержат набор того же элемента ) или ошибочное предположение(такие, что объекты магически клонируются) или что-то не связанное.

Удачное кодирование.


Анализ:

 var mylist = [];
 $.each(data, function (i, item) {
     // creates new object
     var pin = new Pushpin(x, y);
     // property of new object assigned
     // remember that no "duplication" is occurring
     pin.site = item;
     // new object pushed to array
     mylist.push(pin);
 });

Таким образом, pin не будетто же самое , но возможно, что item оценивает один и тот же объект в каждом цикле .(Единственное исключение в этом случае, если конструктор Pushpin использует return для возврата существующего объекта, что было бы действительно здорово.)

0 голосов
/ 17 июня 2011

После прочтения ответа MoarCodePlz я подумал, что, возможно, это поможет обойти проблему «по ссылке».Не проверял это все же.

 var mylist = [];
 $.each(data, function (i, item) {
     // Creates the new object as a part of yourlist
     mylist.push(new Pushpin(x, y));
     // property of new object assigned item
     mylist[x].site = item;
 });
0 голосов
/ 17 июня 2011

Учитывая, что вы находитесь внутри функции, я бы сказал, что да, конечно, все они указывают на один и тот же объект, который вы передаете только по ссылке. Осмотревшись, я наткнулся на это - http://my.opera.com/GreyWyvern/blog/show.dml/1725165 - но не похоже, что есть прямая опция для клонирования объекта Javascript.

Возможно, ваш лучший подход - написать функцию, которая клонирует входной объект и возвращает его как новый экземпляр?

0 голосов
/ 17 июня 2011

Вам нужно объявить вывод var вне .each? затем установите его на новый внутри .each.

var pin;
 var mylist = [];
 $.each(data, function (i, item) {
     try {
         pin = new Pushpin(x, y);
         pin.site = item;
         mylist.push(pin);
     } catch (e) { alert (e); }
 });
...