জাভাস্ক্রিপ্ট ফাংশন আলিয়াসিং কাজ করছে বলে মনে হচ্ছে না


85

আমি কেবল এই প্রশ্নটি পড়ছিলাম এবং ফাংশন-র‍্যাপার পদ্ধতির পরিবর্তে উপনাম পদ্ধতিটি চেষ্টা করতে চেয়েছিলাম, তবে আমি ফায়ারফক্স 3 বা 3.5 বিটা 4 বা গুগল ক্রোম উভয়ই তাদের ডিবাগ উইন্ডোতে এবং এটিতে কাজ করতে পারি বলে মনে হচ্ছিল না and একটি পরীক্ষা ওয়েব পৃষ্ঠাতে।

ফায়ারব্যাগ:

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

যদি আমি এটি কোনও ওয়েব পৃষ্ঠায় রাখি তবে আমার আলিয়াসের কলটি আমাকে এই ত্রুটি দেয়:

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]

ক্রোম (>>> এর স্পষ্টতার জন্য sertedোকানো সহ):

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

এবং পরীক্ষার পৃষ্ঠায়, আমি একই "অবৈধ অনুরোধ" পাই।

আমি কি ভুল কিছু করছি? অন্য কেউ কি এটি পুনরুত্পাদন করতে পারে?

এছাড়াও, অদ্ভুতভাবে যথেষ্ট, আমি কেবল চেষ্টা করেছি এবং এটি আই 8-তে কাজ করে।


4
আইই 8-তে এটি একরকম যাদু ফাংশন বা কিছু হতে পারে।
ম্যাকিয়েজ bebkowski

আমি স্ট্যাকওভারফ্লো / প্রশ্ন / 954417 এ ভুল উত্তরগুলিতে মন্তব্য যুক্ত করেছি এবং সেগুলি এখানে নির্দেশিত করেছি।
অনুদান ওয়াগনার

4
ব্রাউজারগুলির জন্য যা ফাংশন.প্রোটোটাইপ.বাইন্ড পদ্ধতিটিকে সমর্থন করে: উইন্ডো.আমিএলিয়াস = ডকুমেন্ট.সেটমেন্টবিইআইডি.বাইন্ড (দস্তাবেজ); এমডিএন ডক্স অনুসন্ধান করুন, সেখানে একটি বাইন্ড শিম থাকবে।
বেন ফ্লেমিং

উত্তর:


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();">

এইভাবে আপনি আসল বস্তুর রেফারেন্সটি আলগা করবেন না।

২০১২ সালে, 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এবং কল করে getAgegetAge()সঠিকভাবে ফিরে আসবে 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এখন ফিরে আসবে ।200getAgedave


উপরের সব কিসের কথা? আপনার জাভাস্ক্রিপ্ট অবজেক্টের সাথে ফাংশনগুলি 'আলগাভাবে' সংযুক্ত। যেমন আপনি করতে পারেন

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সম্পাদনের জন্য 'সুযোগ' নির্ধারণ করতে পারে নি । সুতরাং এটি বিশ্বব্যাপী 'উইন্ডো' কে 'এটি' হিসাবে পাস করেছে। Now এর মত windowএকটি নেই birthDateসম্পত্তি,ageMethod ফাঁসি ব্যর্থ হবে।

কিভাবে এটি ঠিক করবেন? সরল,

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

উপরের সমস্ত কি বোঝায়? যদি এটি হয়, তবে আপনি কেন উপনামটি করতে সক্ষম নন তা আপনি ব্যাখ্যা করতে সক্ষম হবেন document.getElementById:

var $ = document.getElementById;

$('someElement'); 

$সঙ্গে বলা হয় windowযেমন thisযদি getElementByIdবাস্তবায়ন আশা করছে thisহতে document, এটা ব্যর্থ হবে।

আবার এটি ঠিক করার জন্য, আপনি এটি করতে পারেন

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

তাহলে এটি ইন্টারনেট এক্সপ্লোরারে কেন কাজ করে?

আমি অভ্যন্তরীণ বাস্তবায়ন জানি না getElementByIdআইই এ, কিন্তু jQuery উৎস (একটি মন্তব্য inArray, পদ্ধতি বাস্তবায়ন) বলছেন যে IE তে window == document। যদি এটি হয়, তবে আলিয়াসিংdocument.getElementById উচিত আইই তে কাজ করা।

এটি আরও চিত্রিত করার জন্য, আমি একটি বিস্তৃত উদাহরণ তৈরি করেছি। কটাক্ষপাত আছে 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পদ্ধতি কীভাবে আচরণ করবে তা এখানে's

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
আইই কেন কাজ করে তার জন্য +1। বাকিটি কিছুটা অফ-টপিক তবে সাধারণভাবে এখনও সহায়ক। :)
কেভ

44
দুর্দান্ত উত্তর। যদিও এটির কোনও বিষয় কীভাবে বন্ধ রয়েছে তা আমি দেখতে পাচ্ছি না।
জাস্টিন জনসন 0

সত্যিই খুব সুন্দর উত্তর। কিছুটা খাটো সংস্করণ এখানে লেখা আছে
মার্সেল করপেল

8
আমি স্ট্যাকওভারফ্লোতে দেখেছি সেরা উত্তরগুলির মধ্যে একটি।
ওয়ারবেকার

এটি আইই কেন কাজ করে? কারণ: stackoverflow.com/questions/6994139/... - তাই এই পদ্ধতি বাস্তবায়ন আসলে হতে পারে {ফিরতি জানালা [ID]}, যার ফলে যেকোনো প্রেক্ষাপটে কাজ করবে
Maciej Łebkowski

3

এটি একটি সংক্ষিপ্ত উত্তর।

নিম্নলিখিতটি ফাংশনের একটি অনুলিপি (একটি রেফারেন্স) করে। সমস্যাটি হ'ল এখন ফাংশনটি windowঅবজেক্টটিতে রয়েছে যখন এটি অবজেক্টটিতে লাইভ করার জন্য ডিজাইন করা হয়েছিল document

window.myAlias = document.getElementById

বিকল্পগুলি হ'ল

  • একটি মোড়ক ব্যবহার করতে (ইতিমধ্যে Fabien Ménager দ্বারা উল্লিখিত)
  • অথবা আপনি দুটি এলিয়াস ব্যবহার করতে পারেন।

    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 পদ্ধতি $। প্রক্সি

আপনি এটির মতো নাম রাখতে পারেন:

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

বা

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

+1 কারণ এটি একটি সম্ভাব্য সমাধান। তবে, কঠোরভাবে বলতে গেলে, পর্দার আড়ালে থাকা $.proxyসত্যই একটি মোড়ক।
pimvdb

-6

আপনি আসলে একটি পূর্বনির্ধারিত অবজেক্টের ফাংশন "খাঁটি ওরফে" করতে পারবেন না । অতএব, মোড়ক ছাড়াই আপনি এলিয়াসের নিকটতমতম স্থানটি একই বস্তুর মধ্যে থাকা:

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

4
এটি কিছুটা ভুল। আপনি কোনও ফাংশন 'খাঁটি ওরফে' করতে পারেন তবে ফাংশন বাস্তবায়নের 'এটি' ব্যবহার করে। সুতরাং এটি নির্ভর করে।
সমাধান

দুঃখিত, আমার অর্থ getElementById প্রসঙ্গে ছিল। তুমি ঠিক বলছো. এর প্রতিবিম্বিত করতে আমি উত্তরটি কিছুটা পরিবর্তন করেছি ...
কেভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.