Chrome'un JavaScript konsolu dizileri değerlendirme konusunda tembel mi?


128

Kodla başlayacağım:

var s = ["hi"];
console.log(s);
s[0] = "bye";
console.log(s);

Basit, değil mi? Buna yanıt olarak Firebug şunları söylüyor:

["hi"]
["bye"]

Harika, ancak Chrome'un JavaScript konsolu (7.0.517.41 beta) şunu söylüyor:

["bye"]
["bye"]

Yanlış bir şey mi yaptım yoksa Chrome'un JavaScript konsolu dizimi değerlendirme konusunda son derece tembel mi davranıyor?

görüntü açıklamasını buraya girin


1
Safari'de de aynı davranışı gözlemliyorum - yani bu muhtemelen bir webkit olayıdır. Oldukça şaşırtıcı. Ben buna böcek derim.
Lee

7
Bana göre bir böcek gibi görünüyor. Linux Opera ve Firefox'ta beklenen sonuç görüntülenir, Chrome ve diğer Webkit tabanlı tarayıcılar görüntülenmez. Sorunu Webkit geliştiricilerine bildirmek isteyebilirsiniz: webkit.org/quality/reporting.html
tec

2
Mart 2016 itibariyle bu konu artık yok.
kmonsoor

1
Nisan 2020, Chrome'da bu sorunu yaşıyor. Kodumda Chrome'da bir hata olduğu ortaya çıkan bir hatayı aramak için 2 saat harcadım.
The Fox

1
Ayrıca mavi isimgenin araç ipucunun "Aşağıdaki değer şu anda değerlendirildi" ifadesini de belirtmek gerekir .
user4642212

Yanıtlar:


70

Yorum için teşekkürler, tec. Bu sorunu açıklayan mevcut bir doğrulanmamış Webkit hatasını bulabildim: https://bugs.webkit.org/show_bug.cgi?id=35801 (DÜZENLEME: şimdi düzeltildi!)

Ne kadar bir hata olduğu ve düzeltilebilir olup olmadığı konusunda bazı tartışmalar var gibi görünüyor. Bana kötü bir davranış gibi geliyor. Bu benim için özellikle rahatsız ediciydi çünkü en azından Chrome'da, kod hemen çalıştırılan komut dosyalarında bulunduğunda (sayfa yüklenmeden önce), konsol açıkken bile sayfa her yenilendiğinde ortaya çıkıyor. Konsol henüz etkin olmadığında console.log'un çağrılması, konsolun içereceği çıktıya değil, yalnızca sıraya alınan nesneye bir başvuruyla sonuçlanır. Bu nedenle, dizi (veya herhangi bir nesne) konsol hazır olana kadar değerlendirilmeyecektir. Bu gerçekten bir tembel değerlendirme vakası.

Ancak, kodunuzda bundan kaçınmanın basit bir yolu vardır:

var s = ["hi"];
console.log(s.toString());
s[0] = "bye";
console.log(s.toString());

ToString'i çağırarak, bellekte, konsol hazır olduğunda okuyacağı aşağıdaki ifadelerle değiştirilmeyecek bir temsil yaratırsınız. Konsol çıktısı, nesneyi doğrudan iletmekten biraz farklı, ancak kabul edilebilir görünüyor:

hi
bye

1
Aslında, ilişkilendirilebilir diziler veya diğer nesneler söz konusu olduğunda, bu gerçek bir sorun olabilir, çünkü toString değerli bir şey üretmez. Genel olarak nesneler için kolay bir çözüm var mı?
Eric Mickelsen

29
JSON.stringify ()
draeton

1
webkit birkaç ay önce bunun için bir yama oluşturdu
antony.trupe

1
şunu yapın: console.log (JSON.parse (JSON.stringify (s));
Lee Comstock

Sadece şu anki Chrome sürümünde konsolun geciktiğini ve değerleri tekrar yanlış verdiğini (veya hiç doğru muydu) belirtmek istedim. Örneğin, bir diziyi günlüğe kaydediyordum ve günlüğe kaydettikten sonra en yüksek değeri atıyordum, ancak atılan değer olmadan görünüyordu. ToString () öneriniz, değerleri görmek için ihtiyaç duyduğum yere ulaşmamda gerçekten yardımcı oldu.
Nicholas R. Grant

21

Eric'in açıklamasına göre, console.log()sıraya konulmasından kaynaklanıyor ve dizinin (veya nesnenin) daha sonraki bir değerini yazdırıyor.

5 çözüm olabilir:

1. arr.toString()   // not well for [1,[2,3]] as it shows 1,2,3
2. arr.join()       // same as above
3. arr.slice(0)     // a new array is created, but if arr is [1, 2, arr2, 3] 
                    //   and arr2 changes, then later value might be shown
4. arr.concat()     // a new array is created, but same issue as slice(0)
5. JSON.stringify(arr)  // works well as it takes a snapshot of the whole array 
                        //   or object, and the format shows the exact structure

7

Bir diziyi aşağıdakilerle klonlayabilirsiniz Array#slice:

console.log(s); // ["bye"], i.e. incorrect
console.log(s.slice()); // ["hi"], i.e. correct

Bunun yerine kullanabileceğiniz console.logbu sorunu olmayan bir işlev aşağıdaki gibidir:

console.logShallowCopy = function () {
    function slicedIfArray(arg) {
        return Array.isArray(arg) ? arg.slice() : arg;
    }

    var argsSnapshot = Array.prototype.map.call(arguments, slicedIfArray);
    return console.log.apply(console, argsSnapshot);
};

Nesneler söz konusu olduğunda, ne yazık ki, en iyi yöntem ilk önce WebKit olmayan bir tarayıcıyla hata ayıklamak veya klonlamak için karmaşık bir işlev yazmak gibi görünmektedir. Yalnızca basit nesnelerle çalışıyorsanız, anahtar sırasının önemli olmadığı ve işlevin olmadığı durumlarda, her zaman şunları yapabilirsiniz:

console.logSanitizedCopy = function () {
    var args = Array.prototype.slice.call(arguments);
    var sanitizedArgs = JSON.parse(JSON.stringify(args));

    return console.log.apply(console, sanitizedArgs);
};

Bu yöntemlerin tümü açıkça çok yavaştır, bu nedenle normal console.logs'dekinden daha fazla, hata ayıklamayı bitirdikten sonra onları çıkarmanız gerekir.


2

Bu, Webkit'te düzeltilmiştir, ancak React çerçevesini kullanırken bu benim için bazı durumlarda olur, eğer bu tür sorunlarınız varsa, diğerlerinin önerdiği gibi kullanın:

console.log(JSON.stringify(the_array));

2
Onaylayabilir. ReactSyntheticEvents oturumunu kapatmaya çalışırken bu kelimenin tam anlamıyla en kötüsü. Bir bile JSON.parse(JSON.stringify(event))doğru derinliği / doğruluğu elde edemez. Hata ayıklayıcı ifadeleri, doğru içgörüyü elde etmek için bulduğum tek gerçek çözümdür.
CStumph

1

Bu zaten cevaplandı, ama yine de cevabımı bırakacağım. Bu sorundan muzdarip olmayan basit bir konsol sarıcı uyguladım. JQuery gerektirir.

Sadece uygular log, warnve erroryöntemleri, bunu düzenli ile değiştirilebilir olması için biraz daha eklemek gerekecek console.

var fixedConsole;
(function($) {
    var _freezeOne = function(arg) {
        if (typeof arg === 'object') {
            return $.extend(true, {}, arg);
        } else {
            return arg;
        }
    };
    var _freezeAll = function(args) {
        var frozen = [];
        for (var i=0; i<args.length; i++) {
            frozen.push(_freezeOne(args[i]));
        }
        return frozen;
    };
    fixedConsole = {
        log: function() { console.log.apply(console, _freezeAll(arguments)); },
        warn: function() { console.warn.apply(console, _freezeAll(arguments)); },
        error: function() { console.error.apply(console, _freezeAll(arguments)); }
    };
})(jQuery);

0

Görünüşe göre Chrome, "ön derleme" aşamasında herhangi bir "s" örneğini gerçek diziye gösterici ile değiştiriyor.

Bunun bir yolu, diziyi klonlamak, bunun yerine yeni kopyayı günlüğe kaydetmektir:

var s = ["hi"];
console.log(CloneArray(s));
s[0] = "bye";
console.log(CloneArray(s));

function CloneArray(array)
{
    var clone = new Array();
    for (var i = 0; i < array.length; i++)
        clone[clone.length] = array[i];
    return clone;
}

Bu iyi, ancak sığ bir kopya olduğu için, hala daha ince bir problem olasılığı var. Peki dizi olmayan nesneler ne olacak? (Bunlar şimdi asıl sorun.) "Ön derleme" hakkında söylediklerinizin doğru olduğunu sanmıyorum. Ayrıca, kodda bir hata var: clone [clone.length], clone [i] olmalıdır.
Eric Mickelsen

Hata yok, uyguladım ve iyiydi. klon [clone.length] tam olarak klon [i] gibidir, çünkü dizi 0 uzunluğuyla başlar ve döngü yineleyicisi "i" de öyle. Her neyse, karmaşık nesnelerle nasıl davranacağından emin değilim ama IMO denemeye değer. Dediğim gibi, bu bir çözüm değil, sorunun etrafında bir yol ..
Shadow Wizard is Ear For You

@Shadow Wizard: İyi bir nokta: clone.length her zaman i'ye eşit olacaktır. Nesneler için işe yaramaz. Belki de "her biri için" ile bir çözüm vardır.
Eric Mickelsen

Bunu kastettiğiniz nesneler? var s = {param1: "merhaba", param2: "nasılsın?" }; eğer öyleyse ben test ettim ve s ["param1"] = "güle güle"; beklendiği gibi iyi çalışıyor. Lütfen "nesneler için çalışmayacak" örneğini gönderebilir misiniz? Onu da görecek ve tırmanmaya çalışacağım.
Gölge Sihirbazı Sizin İçin Kulak

@Shadow Wizard: Açıktır ki, işleviniz özellikleri klonlayamaz ve uzunluk özelliği olmayan hiçbir nesne üzerinde çalışmaz. Webkit hatası yalnızca dizileri değil tüm nesneleri etkiler.
Eric Mickelsen

0

Şimdiye kadarki en kısa çözüm, günlüğe kaydetme sırasında olduğu gibi korunacak değerlerin bir klonunu elde etmek için dizi veya nesne yayma sözdizimini kullanmaktır, yani:

console.log({...myObject});
console.log([...myArray]);

ancak sığ bir kopya oluşturduğu için uyarılmalıdır, bu nedenle derin iç içe geçmiş ilkel olmayan değerler klonlanmayacak ve bu nedenle konsolda değiştirilmiş durumlarında gösterilmeyecektir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.