जावास्क्रिप्ट फ़ंक्शन अलियासिंग काम नहीं करता है


85

मैं सिर्फ इस प्रश्न को पढ़ रहा था और फ़ंक्शन-रैपर विधि के बजाय अन्य विधि की कोशिश करना चाहता था, लेकिन मैं फ़ायरफ़ॉक्स 3 या 3.5beta4, या Google Chrome में काम करने के लिए इसे प्राप्त नहीं कर सका, दोनों ने अपनी डिबग विंडो में और एक परीक्षण वेब पेज में।

Firebug:

>>> window.myAlias = document.getElementById
function()
>>> myAlias('item1')
>>> window.myAlias('item1')
>>> document.getElementById('item1')
<div id="item1">

यदि मैं इसे एक वेब पेज में डालता हूं, तो myAlias ​​का कॉल मुझे यह त्रुटि देता है:

uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: file:///[...snip...]/test.html :: <TOP_LEVEL> :: line 7" data: no]

Chrome (>>> के साथ स्पष्टता के लिए सम्मिलित):

>>> window.myAlias = document.getElementById
function getElementById() { [native code] }
>>> window.myAlias('item1')
TypeError: Illegal invocation
>>> document.getElementById('item1')
<div id=?"item1">?

और परीक्षण पृष्ठ में, मुझे वही "अवैध मंगलाचरण" मिलता है।

क्या मुझसे कुछ ग़लत हो रहा है? किसी और को इस पुन: पेश कर सकते हैं?

इसके अलावा, विचित्र रूप से पर्याप्त, मैंने अभी कोशिश की और यह IE8 में काम करता है।


1
IE8 में - यह किसी प्रकार का जादू कार्य या कुछ हो सकता है।
मकीज kebkowski

मैंने stackoverflow.com/questions/954417 पर गलत उत्तरों पर टिप्पणियाँ जोड़ी हैं और उन्हें यहाँ निर्देशित किया है।
ग्रांट वैगनर

1
फंक्शन के लिए जो फंक्शन.प्रोटाइप.बाइंड विधि का समर्थन करते हैं: window.myAlias ​​= document.getElementById.bind (डॉक्यूमेंट); MDN डॉक्स खोजें, एक बाइंड शिम होगा।
बेन फ्लेमिंग

जवाबों:


39

आपको उस विधि को दस्तावेज़ ऑब्जेक्ट पर बांधना होगा। देखो:

>>> $ = document.getElementById
getElementById()
>>> $('bn_home')
[Exception... "Cannot modify properties of a WrappedNative" ... anonymous :: line 72 data: no]
>>> $.call(document, 'bn_home')
<body id="bn_home" onload="init();">

जब आप एक साधारण उपनाम कर रहे हैं, तो फ़ंक्शन को वैश्विक ऑब्जेक्ट पर कहा जाता है, दस्तावेज़ ऑब्जेक्ट पर नहीं। इसे ठीक करने के लिए क्लोजर नामक तकनीक का उपयोग करें:

function makeAlias(object, name) {
    var fn = object ? object[name] : null;
    if (typeof fn == 'undefined') return function () {}
    return function () {
        return fn.apply(object, arguments)
    }
}
$ = makeAlias(document, 'getElementById');

>>> $('bn_home')
<body id="bn_home" onload="init();">

इस तरह आप मूल ऑब्जेक्ट के संदर्भ को ढीला नहीं करते हैं।

2012 में, bindES5 की नई विधि है जो हमें कट्टर तरीके से ऐसा करने की अनुमति देती है:

>>> $ = document.getElementById.bind(document)
>>> $('bn_home')
<body id="bn_home" onload="init();">

4
जो वास्तव में एक आवरण है क्योंकि यह एक नया फ़ंक्शन देता है। मुझे लगता है कि केव के सवाल का जवाब यह है कि यह उन कारणों के लिए संभव नहीं है जो आप ऊपर वर्णित करते हैं। आपके द्वारा यहाँ वर्णित विधि शायद सबसे अच्छा विकल्प है।
जिग्गी

आपकी टिप्पणी के लिए धन्यवाद, मुझे यह महसूस करने के लिए पर्याप्त रूप से नहीं देखा गया था। तो, अन्य प्रश्न पर उत्तरों में वाक्य रचना पूरी तरह से फर्जी है? दिलचस्प ...
केव

188

मैंने इस विशेष व्यवहार को समझने के लिए गहराई से खुदाई की और मुझे लगता है कि मुझे एक अच्छा स्पष्टीकरण मिल गया है।

इससे पहले कि मैं आपको उर्फ ​​क्यों नहीं कर पा document.getElementByIdरहा हूं, मैं यह समझाने की कोशिश करूंगा कि जावास्क्रिप्ट कैसे काम करती है / वस्तुएं काम करती हैं।

जब भी आप एक जावास्क्रिप्ट फ़ंक्शन शुरू करते हैं, तो जावास्क्रिप्ट दुभाषिया एक दायरा निर्धारित करता है और इसे फ़ंक्शन में पास करता है।

निम्नलिखित कार्य पर विचार करें:

function sum(a, b)
{
    return a + b;
}

sum(10, 20); // returns 30;

यह फ़ंक्शन विंडो स्कोप में घोषित किया गया है और जब आप इसे आमंत्रित करते हैं thisतो सम फ़ंक्शन के अंदर का मान वैश्विक Windowऑब्जेक्ट होगा।

'योग' फ़ंक्शन के लिए, यह कोई फर्क नहीं पड़ता कि 'यह' का मान क्या है क्योंकि यह इसका उपयोग नहीं कर रहा है।


निम्नलिखित कार्य पर विचार करें:

function Person(birthDate)
{
    this.birthDate = birthDate;    
    this.getAge = function() { return new Date().getFullYear() - this.birthDate.getFullYear(); };
}

var dave = new Person(new Date(1909, 1, 1)); 
dave.getAge(); //returns 100.

जब आप dave.getAge फ़ंक्शन को कॉल करते हैं, तो जावास्क्रिप्ट दुभाषिया देखता है कि आप daveऑब्जेक्ट पर getAge फ़ंक्शन को कॉल कर रहे हैं , इसलिए यह फ़ंक्शन thisको सेट daveऔर कॉल करता getAgeहै। getAge()सही ढंग से वापस आ जाएगी 100


आप जान सकते हैं कि जावास्क्रिप्ट में आप applyविधि का उपयोग करके गुंजाइश निर्दिष्ट कर सकते हैं । चलो कोशिश करते हैं कि।

var dave = new Person(new Date(1909, 1, 1)); //Age 100 in 2009
var bob = new Person(new Date(1809, 1, 1)); //Age 200 in 2009

dave.getAge.apply(bob); //returns 200.

उपर्युक्त पंक्ति में, जावास्क्रिप्ट को दायरा तय करने देने के बजाय, आप bobऑब्जेक्ट के रूप में स्वयं स्कोप पास कर रहे हैं । भले ही आप ऑब्जेक्ट पर 'विचार' करते getAgeहैं, फिर 200भी वापस आ जाएंगे ।getAgedave


उपरोक्त सभी का क्या मतलब है? कार्य आपके जावास्क्रिप्ट ऑब्जेक्ट्स के साथ 'शिथिल' हैं। जैसे आप कर सकते हैं

var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));

bob.getAge = function() { return -1; };

bob.getAge(); //returns -1
dave.getAge(); //returns 100

चलिए अगला कदम उठाते हैं।

var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;

dave.getAge(); //returns 100;
ageMethod(); //returns ?????

ageMethodनिष्पादन एक त्रुटि फेंकता है! क्या हुआ?

यदि आप मेरे उपरोक्त बिंदुओं को ध्यान से पढ़ते हैं, तो आप ध्यान देंगे कि इस dave.getAgeपद्धति daveको thisऑब्जेक्ट के रूप में बुलाया गया था जबकि जावास्क्रिप्ट ageMethodनिष्पादन के लिए 'गुंजाइश' निर्धारित नहीं कर सकता था। इसलिए इसने वैश्विक 'विंडो' को 'इस' के रूप में पारित किया। अब चूंकि संपत्ति windowनहीं है birthDate, तो ageMethodनिष्पादन विफल हो जाएगा।

इसे कैसे ठीक करें? सरल,

ageMethod.apply(dave); //returns 100.

क्या उपरोक्त सभी समझ में आया? यदि ऐसा होता है, तो आप यह समझाने में सक्षम होंगे कि आप उपनाम क्यों नहीं दे पा रहे हैं document.getElementById:

var $ = document.getElementById;

$('someElement'); 

$के रूप में बुलाया windowजाता है thisऔर यदि getElementByIdकार्यान्वयन होने की उम्मीद thisहै document, तो यह विफल हो जाएगा।

इसे ठीक करने के लिए, आप कर सकते हैं

$.apply(document, ['someElement']);

तो यह Internet Explorer में काम क्यों करता है?

मुझे getElementByIdIE में आंतरिक कार्यान्वयन का पता नहीं है , लेकिन jQuery स्रोत ( inArrayविधि कार्यान्वयन) में एक टिप्पणी कहती है कि IE में window == document,। अगर ऐसा है, तो एलियासिंग document.getElementByIdको IE में काम करना चाहिए।

इसे और स्पष्ट करने के लिए, मैंने एक विस्तृत उदाहरण बनाया है। Personनीचे दिए गए फ़ंक्शन पर एक नज़र डालें।

function Person(birthDate)
{
    var self = this;

    this.birthDate = birthDate;

    this.getAge = function()
    {
        //Let's make sure that getAge method was invoked 
        //with an object which was constructed from our Person function.
        if(this.constructor == Person)
            return new Date().getFullYear() - this.birthDate.getFullYear();
        else
            return -1;
    };

    //Smarter version of getAge function, it will always refer to the object
    //it was created with.
    this.getAgeSmarter = function()
    {
        return self.getAge();
    };

    //Smartest version of getAge function.
    //It will try to use the most appropriate scope.
    this.getAgeSmartest = function()
    {
        var scope = this.constructor == Person ? this : self;
        return scope.getAge();
    };

}

Personउपरोक्त फ़ंक्शन के लिए , यहां विभिन्न getAgeविधियों का व्यवहार कैसे किया जाएगा।

Personफ़ंक्शन का उपयोग करके दो ऑब्जेक्ट बनाएं ।

var yogi = new Person(new Date(1909, 1,1)); //Age is 100
var anotherYogi = new Person(new Date(1809, 1, 1)); //Age is 200

console.log(yogi.getAge()); //Output: 100.

सीधे आगे, getAge पद्धति को yogiवस्तु thisऔर आउटपुट के रूप में वस्तु मिलती है 100


var ageAlias = yogi.getAge;
console.log(ageAlias()); //Output: -1

जावास्क्रिप्ट इंटरप्रिटर windowऑब्जेक्ट को सेट करता है thisऔर हमारी getAgeविधि वापस आ जाएगी -1


console.log(ageAlias.apply(yogi)); //Output: 100

यदि हम सही गुंजाइश निर्धारित करते हैं, तो आप ageAliasविधि का उपयोग कर सकते हैं ।


console.log(ageAlias.apply(anotherYogi)); //Output: 200

यदि हम किसी अन्य व्यक्ति वस्तु में गुजरते हैं, तो यह अभी भी उम्र की सही गणना करेगा।

var ageSmarterAlias = yogi.getAgeSmarter;    
console.log(ageSmarterAlias()); //Output: 100

ageSmarterसमारोह मूल पर कब्जा कर लिया thisवस्तु तो अब आप सही गुंजाइश की आपूर्ति के बारे में चिंता की जरूरत नहीं है।


console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!

इसके साथ समस्या ageSmarterयह है कि आप कभी भी किसी अन्य वस्तु के लिए गुंजाइश निर्धारित नहीं कर सकते हैं।


var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias()); //Output: 100
console.log(ageSmartestAlias.apply(document)); //Output: 100

ageSmartestसमारोह मूल गुंजाइश है, तो गलत गुंजाइश आपूर्ति की है का उपयोग करेगा।


console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200

आप अभी भी किसी अन्य Personऑब्जेक्ट को पास करने में सक्षम होंगे getAgeSmartest। :)


7
IE क्यों काम करता है के लिए +1। बाकी एक सा विषय है, लेकिन अभी भी सामान्य में सहायक है। :)
केव

44
बहुत बढ़िया जवाब। मैं नहीं देखता कि यह कैसे किसी भी विषय से दूर है।
जस्टिन जॉनसन

बहुत अच्छा जवाब, वास्तव में। एक छोटा संस्करण यहाँ लिखा गया है
मार्सेल कोर्पल

8
सबसे अच्छा जवाब मैं stackoverflow पर देखा है में से एक।
वार्नर

यह IE में काम क्यों करता है? क्योंकि: stackoverflow.com/questions/6994139/… - इसलिए यह विधि कार्यान्वयन वास्तव में {रिटर्न विंडो [आईडी]} हो सकता है, इसलिए यह किसी भी संदर्भ में काम करेगा
Maciej kebkowski

3

यह एक संक्षिप्त उत्तर है।

निम्नलिखित फ़ंक्शन की एक प्रति (एक संदर्भ के लिए) बनाता है। समस्या यह है कि अब फ़ंक्शन windowऑब्जेक्ट पर है जब इसे documentऑब्जेक्ट पर रहने के लिए डिज़ाइन किया गया था ।

window.myAlias = document.getElementById

विकल्प हैं

  • एक आवरण का उपयोग करने के लिए (पहले से ही फेबियन मेनेगर द्वारा उल्लिखित)
  • या आप दो उपनामों का उपयोग कर सकते हैं।

    window.d = document // A renamed reference to the object
    window.d.myAlias = window.d.getElementById
    

2

एक और संक्षिप्त जवाब, बस रैपिंग / अलियासिंग console.logऔर इसी तरह की लॉगिंग विधियों के लिए। वे सभी consoleसंदर्भ में होने की उम्मीद करते हैं ।

जब console.logआप या आपके उपयोगकर्ता किसी ऐसे ब्राउज़र का उपयोग करते समय परेशानी में पड़ जाते हैं, तो यह प्रयोग करने योग्य होता है , जो उस ब्राउज़र का उपयोग नहीं करता है (जो हमेशा) इसका समर्थन नहीं करता है । यह उस समस्या का पूर्ण समाधान नहीं है, हालांकि, इसे विस्तारित चेक और एक वापसी की आवश्यकता है - आपका लाभ भिन्न हो सकता है।

चेतावनियों का उपयोग कर उदाहरण

var warn = function(){ console.warn.apply(console, arguments); }

फिर हमेशा की तरह इसका इस्तेमाल करें

warn("I need to debug a number and an object", 9999, { "user" : "Joel" });

यदि आप अपने लॉगिंग तर्कों को एक सरणी में लिपटे हुए देखना पसंद करते हैं (मैं, ज्यादातर समय), के .apply(...)साथ स्थानापन्न .call(...)

साथ काम करना चाहिए console.log(), console.debug(), console.info(), console.warn(), console.error()consoleMDN पर भी देखें ।


1

अन्य महान उत्तरों के अलावा, सरल jQuery विधि $ .proxy है

आप इस तरह से उपनाम कर सकते हैं:

myAlias = $.proxy(document, 'getElementById');

या

myAlias = $.proxy(document.getElementById, document);

+1 क्योंकि यह एक व्यवहार्य समाधान है। लेकिन, कड़ाई से बोलना, पर्दे के पीछे $.proxyभी वास्तव में एक आवरण है।
pimvdb

-6

आप वास्तव में एक पूर्वनिर्धारित वस्तु पर एक फ़ंक्शन "शुद्ध उर्फ" नहीं कर सकते । इसलिए, आप को बिना लपेटे के प्राप्त करने के लिए सबसे करीब उसी वस्तु के भीतर रहकर प्राप्त कर सकते हैं:

>>> document.s = document.getElementById;
>>> document.s('myid');
<div id="myid">

5
यह थोड़ा गलत है। आप 'शुद्ध उर्फ' एक फ़ंक्शन प्रदान कर सकते हैं, बशर्ते कि फ़ंक्शन कार्यान्वयन 'इस' का उपयोग करता है। तो यह निर्भर करता है।
सोल्यूयोगी

क्षमा करें, मेरा मतलब getElementById के संदर्भ में है। आप सही हे। मैंने इसे दर्शाने के लिए उत्तर को थोड़ा बदल दिया है ...
केव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.