खोज…
टिप्पणियों
स्कोप वह संदर्भ है जिसमें चर रहते हैं और उसी दायरे में अन्य कोड द्वारा पहुँचा जा सकता है। क्योंकि जावास्क्रिप्ट को मोटे तौर पर एक कार्यात्मक प्रोग्रामिंग भाषा के रूप में इस्तेमाल किया जा सकता है, चर और कार्यों के दायरे को जानना महत्वपूर्ण है क्योंकि यह बग्स और अप्रत्याशित व्यवहार को रोकने में मदद करता है।
Var और let के बीच अंतर
(नोट: सभी के उपयोग के उदाहरण let
भी के लिए मान्य हैं const
)
var
जावास्क्रिप्ट के सभी संस्करणों में उपलब्ध है, जबकि let
और const
ECMAScript 6 का हिस्सा हैं और केवल कुछ नए ब्राउज़रों में उपलब्ध हैं ।
जब यह घोषित किया जाता है, तो var
को सम्मिलित फ़ंक्शन या वैश्विक स्थान पर स्कोप किया जाता है:
var x = 4; // global scope
function DoThings() {
var x = 7; // function scope
console.log(x);
}
console.log(x); // >> 4
DoThings(); // >> 7
console.log(x); // >> 4
इसका मतलब है कि if
बयान और सभी समान ब्लॉक का निर्माण "बच गया":
var x = 4;
if (true) {
var x = 7;
}
console.log(x); // >> 7
for (var i = 0; i < 4; i++) {
var j = 10;
}
console.log(i); // >> 4
console.log(j); // >> 10
तुलनात्मक रूप से, let
ब्लॉक scoped है:
let x = 4;
if (true) {
let x = 7;
console.log(x); // >> 7
}
console.log(x); // >> 4
for (let i = 0; i < 4; i++) {
let j = 10;
}
console.log(i); // >> "ReferenceError: i is not defined"
console.log(j); // >> "ReferenceError: j is not defined"
ध्यान दें कि i
और j
केवल लूप के for
घोषित किए गए हैं और इसलिए इसके बाहर अघोषित है।
कई अन्य महत्वपूर्ण अंतर हैं:
वैश्विक चर घोषणा
शीर्ष गुंजाइश (किसी भी फ़ंक्शन और ब्लॉक के बाहर) में, var
घोषणाओं ने वैश्विक ऑब्जेक्ट में एक तत्व डाल दिया। let
नहीं है:
var x = 4;
let y = 7;
console.log(this.x); // >> 4
console.log(this.y); // >> undefined
पुन: घोषणा
एक चर दो बार की घोषणा का उपयोग कर var
एक त्रुटि का उत्पादन नहीं करता (भले ही यह यह एक बार घोषित करने के बराबर है):
var x = 4;
var x = 7;
साथ let
, यह एक त्रुटि पैदा करता है:
let x = 4;
let x = 7;
TypeError: Identifier
x
पहले ही घोषित किया जा चुका है
जब y
को var
साथ घोषित किया जाता है तो वही सच होता है:
var y = 4;
let y = 7;
TypeError: Identifier
y
पहले ही घोषित किया जा चुका है
हालाँकि, दो के साथ घोषित चर का पुन: उपयोग नहीं किया जा सकता है (फिर से घोषित नहीं) एक नेस्टेड ब्लॉक में
let i = 5;
{
let i = 6;
console.log(i); // >> 6
}
console.log(i); // >> 5
ब्लॉक के भीतर बाहरी i
पहुँचा जा सकता है लेकिन अगर ब्लॉक के भीतर एक है let
के लिए घोषणा i
, बाहरी i
पहुँचा नहीं जा सकता है और एक फेंक होगा ReferenceError
अगर पहले दूसरी घोषित किया जाता है प्रयोग किया जाता है।
let i = 5;
{
i = 6; // outer i is unavailable within the Temporal Dead Zone
let i;
}
संदर्भ: मैं परिभाषित नहीं है
उत्थापन
चर के साथ दोनों घोषित var
और let
जाते हैं फहराया । अंतर यह है कि एक चर घोषित साथ है var
का अपना काम करने से पहले संदर्भित किया जा सकता है, क्योंकि यह स्वचालित रूप से सौंप दिया जाता है (साथ undefined
अपने मूल्य के रूप में), लेकिन let
नहीं-यह विशेष रूप से चर लागू किए जाने से पहले घोषित किए जाने की आवश्यकता कर सकते हैं:
console.log(x); // >> undefined
console.log(y); // >> "ReferenceError: `y` is not defined"
//OR >> "ReferenceError: can't access lexical declaration `y` before initialization"
var x = 4;
let y = 7;
ब्लॉक और let
या const
घोषणा के बीच के क्षेत्र को टेम्पोरल डेड जोन के रूप में जाना जाता है, और इस क्षेत्र में चर के किसी भी संदर्भ के कारण एक ReferenceError
पैदा होगा। यह तब भी होता है जब घोषित किए जाने से पहले चर को सौंपा गया हो :
y=7; // >> "ReferenceError: `y` is not defined"
let y;
गैर-सख्त-मोड में, किसी भी घोषणा के बिना एक चर के मूल्य को निर्दिष्ट करना, स्वचालित रूप से वैश्विक दायरे में चर घोषित करता है । इस मामले में, के बजाय y
स्वचालित रूप से वैश्विक क्षेत्र में घोषित किया गया, let
भंडार वेरिएबल का नाम ( y
) और लाइन जहां यह घोषित / आरंभ नहीं हो जाता से पहले किसी भी उपयोग या इसे करने के लिए काम की अनुमति नहीं है।
बंद
जब कोई फ़ंक्शन घोषित किया जाता है, तो इसकी घोषणा के संदर्भ में चर इसके दायरे में कैप्चर किए जाते हैं। उदाहरण के लिए, नीचे दिए गए कोड में, चर x
बाहरी दायरे में एक मूल्य के लिए बाध्य है, और फिर x
के संदर्भ को bar
के संदर्भ में कैप्चर किया गया है:
var x = 4; // declaration in outer scope
function bar() {
console.log(x); // outer scope is captured on declaration
}
bar(); // prints 4 to console
नमूना उत्पादन:
4
"कैप्चरिंग" गुंजाइश की यह अवधारणा दिलचस्प है क्योंकि हम बाहरी दायरे से बाहर निकलने के बाद भी बाहरी दायरे से चर का उपयोग और संशोधित कर सकते हैं। उदाहरण के लिए, निम्नलिखित पर विचार करें:
function foo() {
var x = 4; // declaration in outer scope
function bar() {
console.log(x); // outer scope is captured on declaration
}
return bar;
// x goes out of scope after foo returns
}
var barWithX = foo();
barWithX(); // we can still access x
नमूना उत्पादन:
4
उपरोक्त उदाहरण में, जब foo
को बुलाया जाता है, तो इसका संदर्भ फ़ंक्शन bar
में कैप्चर किया जाता है। तो यह वापस आने के बाद भी, bar
अभी भी चर x
को एक्सेस और संशोधित कर सकता है। फ़ंक्शन foo
, जिसका संदर्भ किसी अन्य फ़ंक्शन में कैप्चर किया गया है, को एक क्लोजर कहा जाता है।
निजी डेटा
यह हमें कुछ दिलचस्प चीजें करने देता है, जैसे "निजी" चर को परिभाषित करना जो केवल एक विशिष्ट फ़ंक्शन या फ़ंक्शन के सेट के लिए दिखाई देते हैं। एक आकस्मिक (लेकिन लोकप्रिय) उदाहरण:
function makeCounter() {
var counter = 0;
return {
value: function () {
return counter;
},
increment: function () {
counter++;
}
};
}
var a = makeCounter();
var b = makeCounter();
a.increment();
console.log(a.value());
console.log(b.value());
नमूना उत्पादन:
1 0
जब makeCounter()
कहा जाता है, तो उस फ़ंक्शन के संदर्भ का एक स्नैपशॉट सहेजा जाता है। makeCounter()
के अंदर सभी कोड उनके निष्पादन में उस स्नैपशॉट का उपयोग करेंगे। makeCounter()
की दो कॉल इस प्रकार दो अलग-अलग स्नैपशॉट बनाएगी, जिसमें counter
की अपनी प्रति होगी।
तुरंत-समारोह फ़ंक्शन अभिव्यक्ति (IIFE)
क्लोजर का उपयोग वैश्विक नेमस्पेस प्रदूषण को रोकने के लिए भी किया जाता है, अक्सर तुरंत-आह्वान किए गए फ़ंक्शन के उपयोग के माध्यम से।
तुरंत-इन-फ़ंक्शन फ़ंक्शन अभिव्यक्तियाँ (या, शायद अधिक सहज रूप से, स्व-निष्पादित अनाम कार्य ) अनिवार्य रूप से बंद हो जाती हैं जिन्हें घोषणा के बाद सही कहा जाता है। आईआईएफई के साथ सामान्य विचार एक अलग संदर्भ बनाने के साइड-इफेक्ट को लागू करना है जो केवल आईआईएफई के भीतर कोड के लिए सुलभ है।
मान लीजिए कि हम $
साथ jQuery
को संदर्भित करना चाहते हैं। एक IIFE का उपयोग किए बिना, अनुभवहीन विधि पर विचार करें:
var $ = jQuery;
// we've just polluted the global namespace by assigning window.$ to jQuery
निम्नलिखित उदाहरण में, एक IIFE का उपयोग यह सुनिश्चित करने के लिए किया जाता है कि $
केवल बंद किए गए संदर्भ में jQuery
लिए बाध्य है:
(function ($) {
// $ is assigned to jQuery here
})(jQuery);
// but window.$ binding doesn't exist, so no pollution
क्लोजर पर अधिक जानकारी के लिए Stackoverflow पर विहित जवाब देखें।
उत्थापन
क्या फहरा रहा है?
उत्थापन एक तंत्र है जो सभी चर और फ़ंक्शन घोषणाओं को उनके दायरे के शीर्ष पर ले जाता है। हालांकि, चर असाइनमेंट अभी भी होते हैं जहां वे मूल रूप से थे।
उदाहरण के लिए, निम्नलिखित कोड पर विचार करें:
console.log(foo); // → undefined
var foo = 42;
console.log(foo); // → 42
उपरोक्त कोड इस प्रकार है:
var foo; // → Hoisted variable declaration
console.log(foo); // → undefined
foo = 42; // → variable assignment remains in the same place
console.log(foo); // → 42
ध्यान दें कि उपरोक्त undefined
उत्थापन के कारण चलने के परिणामस्वरूप not defined
नहीं के समान not defined
:
console.log(foo); // → foo is not defined
एक समान सिद्धांत कार्यों पर लागू होता है। जब फ़ंक्शन एक चर (यानी एक फ़ंक्शन अभिव्यक्ति ) को सौंपा जाता है, तो चर घोषणा को फहराया जाता है जबकि असाइनमेंट उसी स्थान पर रहता है। निम्नलिखित दो कोड स्निपेट समतुल्य हैं।
console.log(foo(2, 3)); // → foo is not a function
var foo = function(a, b) {
return a * b;
}
var foo;
console.log(foo(2, 3)); // → foo is not a function
foo = function(a, b) {
return a * b;
}
फ़ंक्शन स्टेटमेंट की घोषणा करते समय , एक अलग परिदृश्य होता है। फ़ंक्शन स्टेटमेंट के विपरीत, फ़ंक्शन घोषणाएँ उनके दायरे के शीर्ष पर फहराई जाती हैं। निम्नलिखित कोड पर विचार करें:
console.log(foo(2, 3)); // → 6
function foo(a, b) {
return a * b;
}
उपरोक्त कोड उत्थापन के कारण अगले कोड स्निपेट के समान है:
function foo(a, b) {
return a * b;
}
console.log(foo(2, 3)); // → 6
यहाँ कुछ उदाहरण हैं कि क्या है और क्या नहीं फहरा रहा है:
// Valid code:
foo();
function foo() {}
// Invalid code:
bar(); // → TypeError: bar is not a function
var bar = function () {};
// Valid code:
foo();
function foo() {
bar();
}
function bar() {}
// Invalid code:
foo();
function foo() {
bar(); // → TypeError: bar is not a function
}
var bar = function () {};
// (E) valid:
function foo() {
bar();
}
var bar = function(){};
foo();
उत्थापन की सीमा
एक वैरिएबल को प्रारंभ करना उत्थापन नहीं किया जा सकता है या सरल जावास्क्रिप्ट होइस्ट घोषणाओं में आरंभीकरण नहीं है।
उदाहरण के लिए: नीचे की स्क्रिप्ट अलग-अलग आउटपुट देगी।
var x = 2;
var y = 4;
alert(x + y);
यह आपको 6. का आउटपुट देगा लेकिन यह ...
var x = 2;
alert(x + y);
var y = 4;
यह आपको NaN का आउटपुट देगा। चूँकि हम y के मान को आरम्भ कर रहे हैं, जावास्क्रिप्ट उत्थापन नहीं हो रहा है, इसलिए y मान अपरिभाषित हो जाएगा। जावास्क्रिप्ट विचार करेगा कि y अभी तक घोषित नहीं है।
तो दूसरा उदाहरण नीचे के रूप में ही है।
var x = 2;
var y;
alert(x + y);
y = 4;
यह आपको NaN का आउटपुट देगा।
Var के बजाय loops में जाने का उपयोग करें (हैंडलर उदाहरण पर क्लिक करें)
मान लें कि हमें loadedData
सरणी के प्रत्येक टुकड़े के लिए एक बटन जोड़ने की आवश्यकता है (उदाहरण के लिए, प्रत्येक बटन को डेटा दिखाने वाला एक स्लाइडर होना चाहिए; सरलता के लिए, हम सिर्फ एक संदेश को सचेत करेंगे)। कुछ इस तरह की कोशिश कर सकते हैं:
for(var i = 0; i < loadedData.length; i++)
jQuery("#container").append("<a class='button'>"+loadedData[i].label+"</a>")
.children().last() // now let's attach a handler to the button which is a child
.on("click",function() { alert(loadedData[i].content); });
लेकिन अलर्ट के बजाय, प्रत्येक बटन के कारण होगा
TypeError: loadData [i] अपरिभाषित है
त्रुटि। इसका कारण यह है कि i
का दायरा वैश्विक क्षेत्र (या एक कार्यक्षेत्र) है और लूप के बाद, i == 3
। क्या हम की जरूरत है "के राज्य याद करने के लिए नहीं है i
"। इसे let
का उपयोग करके किया जा सकता है:
for(let i = 0; i < loadedData.length; i++)
jQuery("#container").append("<a class='button'>"+loadedData[i].label+"</a>")
.children().last() // now let's attach a handler to the button which is a child
.on("click",function() { alert(loadedData[i].content); });
loadedData
कोड का एक उदाहरण इस कोड के साथ परीक्षण किया जाना है:
var loadedData = [
{ label:"apple", content:"green and round" },
{ label:"blackberry", content:"small black or blue" },
{ label:"pineapple", content:"weird stuff.. difficult to explain the shape" }
];
विधि आह्वान
एक वस्तु की एक विधि के रूप में एक समारोह लागू की मूल्य this
उस वस्तु हो जाएगा।
var obj = {
name: "Foo",
print: function () {
console.log(this.name)
}
}
हम अब ओब्ज की एक विधि के रूप में प्रिंट का आह्वान कर सकते हैं। this
obj होगा
obj.print();
इस प्रकार लॉग होगा:
फू
अनाम आह्वान
किसी फ़ंक्शन को एक अनाम फ़ंक्शन के रूप में आमंत्रित करना, this
वैश्विक ऑब्जेक्ट (ब्राउज़र में self
) होगा।
function func() {
return this;
}
func() === window; // true
ECMAScript 5 के सख्त मोड में , this
undefined
होगा यदि फ़ंक्शन को गुमनाम रूप से लागू किया जाता है।
(function () {
"use strict";
func();
}())
यह आउटपुट करेगा
undefined
विधायक आह्वान
जब एक फ़ंक्शन को new
कीवर्ड के साथ एक निर्माता के रूप में आमंत्रित किया जाता है, तो this
निर्माण की जा रही वस्तु का मूल्य लेता है
function Obj(name) {
this.name = name;
}
var obj = new Obj("Foo");
console.log(obj);
यह लॉग होगा
{नाम: "फू"}
एरो फंक्शन इनवोकेशन
तीर कार्यों का उपयोग करते समय this
संलग्नित निष्पादन संदर्भ से मूल्य है लेता है this
(यह है कि, this
तीर कार्यों में हमेशा की तरह गतिशील गुंजाइश बजाय शाब्दिक गुंजाइश है)। वैश्विक कोड में (वह कोड जो किसी फ़ंक्शन से संबंधित नहीं है) यह वैश्विक ऑब्जेक्ट होगा। और यह इस तरह से रखता है, भले ही आप यहां वर्णित अन्य तरीकों में से किसी भी विधि से तीर संकेतन के साथ घोषित फ़ंक्शन को लागू करते हों।
var globalThis = this; //"window" in a browser, or "global" in Node.js
var foo = (() => this);
console.log(foo() === globalThis); //true
var obj = { name: "Foo" };
console.log(foo.call(obj) === globalThis); //true
यह देखें कि this
विधि जिस ऑब्जेक्ट पर कॉल की गई थी, उसका संदर्भ देने के बजाय संदर्भ को कैसे विरासत में मिला है।
var globalThis = this;
var obj = {
withoutArrow: function() {
return this;
},
withArrow: () => this
};
console.log(obj.withoutArrow() === obj); //true
console.log(obj.withArrow() === globalThis); //true
var fn = obj.withoutArrow; //no longer calling withoutArrow as a method
var fn2 = obj.withArrow;
console.log(fn() === globalThis); //true
console.log(fn2() === globalThis); //true
सिंटैक्स और आह्वान लागू करें और कॉल करें।
apply
और call
हर कार्य में तरीकों इसके लिए एक कस्टम मूल्य प्रदान करने की अनुमति this
।
function print() {
console.log(this.toPrint);
}
print.apply({ toPrint: "Foo" }); // >> "Foo"
print.call({ toPrint: "Foo" }); // >> "Foo"
आप देख सकते हैं कि ऊपर उपयोग किए गए दोनों इनवोकेशन के लिए सिंटैक्स समान हैं। यानी हस्ताक्षर समान दिखते हैं।
लेकिन उनके उपयोग में एक छोटा सा अंतर है, क्योंकि हम कार्यों के साथ काम कर रहे हैं और उनके स्कोप को बदल रहे हैं, हमें अभी भी फ़ंक्शन के लिए पारित मूल तर्कों को बनाए रखने की आवश्यकता है। लक्ष्य समारोह में तर्क पास करने के लिए apply
और call
दोनों निम्नानुसार हैं:
function speak() {
var sentences = Array.prototype.slice.call(arguments);
console.log(this.name+": "+sentences);
}
var person = { name: "Sunny" };
speak.apply(person, ["I", "Code", "Startups"]); // >> "Sunny: I Code Startups"
speak.call(person, "I", "<3", "Javascript"); // >> "Sunny: I <3 Javascript"
apply
सूचना आपको arguments
की सूची के रूप में एक Array
या arguments
वस्तु (सरणी जैसी) पास apply
अनुमति देती है, जबकि, call
लिए आपको प्रत्येक तर्क को अलग से पारित करने की आवश्यकता होती है।
इन दोनों तरीकों आप ECMAScript की मूल के एक गरीब संस्करण को लागू करने की तरह है, के रूप में आप चाहते हैं कल्पना के रूप में प्राप्त करने के लिए स्वतंत्रता देना bind
एक समारोह है कि हमेशा एक मूल कार्य से किसी वस्तु की एक विधि के रूप बुलाया जाएगा बनाने के लिए।
function bind (func, obj) {
return function () {
return func.apply(obj, Array.prototype.slice.call(arguments, 1));
}
}
var obj = { name: "Foo" };
function print() {
console.log(this.name);
}
printObj = bind(print, obj);
printObj();
यह लॉग होगा
"फू"
bind
फंक्शन बहुत चल रहा है
-
obj
के मूल्य के रूप में इस्तेमाल किया जाएगाthis
- फ़ंक्शन के लिए तर्कों को अग्रेषित करें
- और फिर मूल्य वापस करें
बाध्यता का आह्वान
प्रत्येक फ़ंक्शन की bind
पद्धति आपको उस फ़ंक्शन के नए संस्करण को उस संदर्भ के साथ बनाने की अनुमति देती है, जो किसी विशिष्ट ऑब्जेक्ट के लिए कड़ाई से बाध्य है। किसी फ़ंक्शन को ऑब्जेक्ट की विधि के रूप में कहा जाना मजबूर करने के लिए विशेष रूप से उपयोगी है।
var obj = { foo: 'bar' };
function foo() {
return this.foo;
}
fooObj = foo.bind(obj);
fooObj();
यह लॉग करेगा:
बार