2010-01-27 13 views
7

साथ जावास्क्रिप्ट त्रुटि मैं निम्नलिखित कोड जो एफएफ/क्रोम में काम करता हैकेवल आईई getElementsByTagName

var stack = [Array.prototype.slice.call(document.getElementsByTagName("body")[0].childNodes)], nodes, node, parent, text, offset; 
while (stack.length) { 
    nodes = stack.pop(); 
    for (var i=0, n=nodes.length; i<n; ++i) { 
     node = nodes[i]; 
     switch (node.nodeType) { 
      case Node.ELEMENT_NODE: 
       if (node.nodeName.toUpperCase() !== "SCRIPT") { 
        stack.push(Array.prototype.slice.call(node.childNodes)); 
       } 
       break; 
      case Node.TEXT_NODE: 
       text = node.nodeValue; 
       offset = text.indexOf("[test="); 
       if (offset >= 0 && text.substr(offset).match(/^(\[test=(\d+)\])/)) { 
        parent = node.parentNode; 
        var before = document.createTextNode(text.substr(0, offset)); 
         link = document.createElement("a"), 
         after = document.createTextNode(text.substr(offset + RegExp.$1.length)); 
        link.appendChild(document.createTextNode(text.substr(offset, RegExp.$1.length))); 
        link.setAttribute("href", "http://example.com/" + RegExp.$2); 
        parent.insertBefore(after, node); 
        parent.insertBefore(link, after); 
        parent.insertBefore(before, link); 
        parent.removeChild(node); 
        stack.push([after]); 
       } 
     } 
    } 
} 

मूल रूप से क्या यह करता है अगर यह पाता है [परीक्षण = 25] पेज में यह एक कड़ी में बदल देता है जो example.com/25 को

आईई में मैं निम्नलिखित त्रुटि मिलती है बताते हैं: JScript वस्तु पहली पंक्ति पर अपेक्षित:

var stack = [Array.prototype.slice.call(document.getElementsByTagName("body")[0].childNodes)], nodes, node, parent, text, offset; 

यह त्रुटि दोनों IE7 और IE8 में होता है।

किसी भी मदद की सराहना की जाएगी।

धन्यवाद।

उत्तर

12

यह रूप में childNodes संपत्ति (या विभिन्न अन्य डोम विधि) द्वारा दिया एक NodeList वस्तु पर Array.prototype.slice कॉल करने के लिए कानूनी नहीं है।

आम तौर पर यह कुछ भी लेकिन Thing का एक उदाहरण पर Thing.prototype.method कॉल करने के लिए कानूनी नहीं होगा, हालांकि ब्राउज़रों पारंपरिक रूप से अनुमति दी है - और ECMAScript तीसरा संस्करण मानक की आवश्यकता है - कई Array.prototype तरीकों के लिए एक विशेष मामला इतना है कि वे पर कहा जा सकता है कोई देशी-जावास्क्रिप्ट ऑब्जेक्ट जो Array की तरह पर्याप्त है। इसका मतलब है, विशेष रूप से, कि वे arguments ऑब्जेक्ट पर उपयोग किए जा सकते हैं, जो Array जैसा दिखता है लेकिन वास्तव में नहीं है।

हालांकि, NodeList और डीओएम में अन्य संग्रह वस्तुओं को मूल जावास्क्रिप्ट ऑब्जेक्ट्स के रूप में परिभाषित नहीं किया गया है; उन्हें 'होस्ट ऑब्जेक्ट' होने की इजाजत है, जिन्हें पूरी तरह से ब्राउज़र द्वारा लागू किया जाता है, न कि भाषा। सभी दांव मेजबान वस्तुओं के लिए बंद कर रहे हैं ...

Whether the slice function can be applied successfully to a host object is implementation-dependent.

तो Array.prototype.slice NodeList के लिए संस्करण 8 से पहले, वास्तव में काम नहीं कर सकता, और IE में, यह नहीं होगा।

आप एक NodeList का सादे-सरणी प्रतिलिपि बनाना चाहते हैं, तो आप इसे लंबे समय तक लेकिन सुरक्षित तरीके से करना होगा:

Array.fromSequence= function(seq) { 
    var arr= new Array(seq.length); 
    for (var i= seq.length; i-->0;) 
     if (i in seq) 
      arr[i]= seq[i]; 
    return arr; 
}; 

var stack = [Array.fromSequence(document.body.childNodes)]; 

संयोग से, आप का उपयोग करके थोड़ा सरल linkifier कि कर सकते हैं textnode.splitText, और मैं वैश्विक RegExp गुणों का उपयोग करने के बारे में बहुत सावधान रहूंगा, जैसे कि किसी भी अप्रत्याशित रेगेक्स कार्य में हस्तक्षेप करने वाली कॉल में से एक में खो जाएगा। मैच ऑब्जेक्ट को देखना आम तौर पर बेहतर होता है। मूल रूप से एक ही समस्या पर एक और हमले के लिए this question देखें।

+0

+1। और पूरी तरह से एक संयोग पक्ष के रूप में नोट: कुछ फ़ायरफ़ॉक्स जावास्क्रिप्ट मानक जो मैंने हाल ही में किया था, मैंने पाया कि एक खाली शाब्दिक '[]' और 'पुश' का उपयोग करके सरणी बनाना, विडंबनात्मक रूप से पर्याप्त है, यहां दिखाए गए तरीके से तेज़ है। –

+0

दिलचस्प! 'पुश' ऊपर की तरह एक स्पैस-सूची (गायब वस्तुओं के साथ) को फिर से नहीं बना सकता है, लेकिन एक नोडलिस्ट के लिए आपको इसकी आवश्यकता नहीं होगी। – bobince

+0

जानकारी के लिए धन्यवाद और विशेष रूप से उस अन्य प्रश्न के लिंक। मुझे ठीक इसी की तलाश थी। – Rob

2

बजाय इस उपयोग करके देखें:

var stack = [Array().slice.call(document.getElementsByTagName("body")[0].childNodes)] 

वहाँ IE और प्रोटोटाइप/कंस्ट्रक्टर्स के साथ कुछ funkyness है। मै मैक पर अभी परीक्षण नहीं कर सकता।

अधिक यहाँ जानकारी: Difference between Array.slice and Array().slice

3

मुझे लगता है कि इस वजह से getElementsByTagname एक nodelist रिटर्न - नहीं एक सरणी (हालांकि कि में [] ऑपरेटर काम की तरह कुछ बातें की तरह वे सरणियों पर काम करते हैं, वे ही नहीं हैं)

शायद यह हल किया जा सकता कम जटिल तरीके से:

var els = document.body.getElementsByTagName("*"); 
for (var i=0, numEls=els.length, el; i<numEls; i++){ 
    el = els.item(i); 
    el.normalize();   
    for (var j=0, chs = el.childNodes, numChs=chs.length, ch; j<numChs; j++){ 
     ch = chs.item(j); 
     if (ch.nodeType==Node.TEXT_NODE){ 
      //you code for replacing text with link goes here 
      //ps i suggest using ch.data instead of ch.nodeValue 
     } 
    } 
} 
+0

'getElementsByTagName ("*") का उपयोग करना एक अच्छा विचार है, लेकिन याद रखें कि यह एक लाइव नोडलिस्ट है: जैसा कि आप पृष्ठ के लिंक जोड़ते हैं, इसे अतिरिक्त आइटम प्राप्त होंगे। इसका मतलब यह होगा कि आखिरी संख्या में जोड़े गए तत्वों की जांच नहीं की जाएगी ('numEls'-remembering optimization के कारण), और यदि प्रतिस्थापन टेक्स्ट में खोजी गई पाठ हो सकती है तो यह एक पागल रिकर्सिव प्रतिस्थापन करेगा। मूल प्रयास के रूप में नोडलिस्ट की प्रतिलिपि लेने के लिए बेहतर है, या बस नोडलिस्ट को रिवर्स में फिर से चलाने के लिए बेहतर है। – bobince

+0

@ बॉबिन: वास्तव में, आप सही हैं :) इसे इंगित करने के लिए धन्यवाद। लेकिन उस स्थिति में, मुझे लगता है कि मैं एक सरणी में मिलान करने वाले सभी टेक्स्टनोड को स्टोर करने की कोशिश करता हूं और फिर लूप के बाहर, प्रतिस्थापन करने के लिए फिर से सरणी पर लूप - मुझे लगता है कि किसी भी स्पष्ट नोड स्थिति की आवश्यकता के बिना संभव होना चाहिए। सूची में चलने के लिए मुझे आपके सुझाव के बारे में सोचना होगा ... मैं बहुत लंबा रहा हूं और नींद की जरूरत है। लेकिन मैं इसके बारे में सोचूंगा - धन्यवाद! –

संबंधित मुद्दे