JS დახურვა. Circuits in JavaScript: პრაქტიკული მაგალითი, თვისებები და წესები

Გამარჯობა ყველას! ამ სტატიაში ჩვენ შევხედავთ რა არის დახურვის JavaScript.

ეს არის საკმაოდ მარტივი თემა, მაგრამ ეს მოითხოვს გაგება. პირველი, მოდით შევხედოთ რა ხდება შიგნით ფუნქცია.

ფუნქცია მისალოცი (სახელი) (
/ Lexicalenvironment \u003d (სახელი: "ნიკოლაი", ტექსტი: undefined)
var text \u003d "გამარჯობა" + სახელი;
// lexicalenvironment \u003d (სახელი: "ნიკოლაი", ტექსტი: "გამარჯობა, ნიკოლაი")
გაფრთხილება (ტექსტი);
}

მისალოცი ("ნიკოლაი");

რა ხდება აქ და რა არის Lexicalenvironment? მოდით გაერკვნენ.

როდესაც ფუნქცია ეწოდება, ის ქმნის ობიექტს Lexicalenvironmentრომელშიც ყველა ადგილობრივი ცვლადი და ფუნქციები ჩაწერილია, ასევე გარე მასშტაბის მითითებით (ამის შესახებ). ჩვენს შემთხვევაში, ჩვენ გვაქვს ადგილობრივი ცვლადი სახელი.რომელიც დაუყოვნებლივ აქვს ღირებულება (მაშინ, რომ ჩვენ გადავიდეთ) და ეს "ნიკოლაი". ერთ-ერთ სტატიაში მე უკვე დავწერე, თუმცა შეგახსენებთ, რომ ინტერპორტორმა ყველაფერი კარგად იცის ყველა ცვლადის შესახებ. ამის შესახებ, რომ ფუნქციის დასაწყისში უკვე ცვალებადია ტექსტი., თარჯიმანი იცის ამის შესახებ, მაგრამ მას შემდეგ, რაც ჩვენ ჯერ კიდევ არ მივაღწიეთ ამ ტიპის ცვლადის დავალებას, ტოლია განუსაზღვრელი.. ახლა ჩვენ ვატარებთ ცვლადი ღირებულებას და ჩვენს ობიექტს Lexicalenvironment ცვლილებები. მისი ქონება ტექსტი. ეს ხდება ტოლია ის ფაქტი, რომ ჩვენ ჩაწერილი ("გამარჯობა, ნიკოლაი" ჩვენს შემთხვევაში). მას შემდეგ, რაც ფუნქცია შემუშავდა, ობიექტი Lexicalenvironment განადგურება. შემდგომი ზარები, ის კვლავ შეიქმნება და ა.შ.

ჩვენ ახლა მივმართავთ მომდევნო მაგალითს. მითხარი, რა მოხდება ამ შემთხვევაში?

V var b \u003d 2;
ფუნქცია x (a) (
alert (a + b);
}
x (1);

ეგონა? მე ვფიქრობ, რომ ყველაზე მეტად უპასუხა, რომ ნომერი 3 იქნება ნაჩვენები, და ეს არის სწორი პასუხი, თუმცა შეგიძლიათ გითხრათ, თუ როგორ შეიტყო თარჯიმანი ცვლადი ბ.? ყოველივე ამის შემდეგ, ეს არ არის სხეულის ფუნქციაში. თუ არა, გავიგოთ.

სინამდვილეში javaScript. არსებობს ფარული ქონება მოუწოდა [] . როდესაც ფუნქცია გამოცხადდება, ის ყოველთვის გამოცხადდა სადღაც. ეს ფუნქცია შეიძლება იყოს სხვა ფუნქციაში, შეიძლება იყოს გლობალურ ობიექტში და ა.შ. ჩვენს შემთხვევაში, ფუნქცია გლობალურ ობიექტში გამოცხადდა. ფანჯარა., ამიტომ, ქონება x. [] \u003d ფანჯარა.

V var b \u003d 2;
ფუნქცია x (a) (// x [] \u003d window
// lexicalenvironment \u003d (a: 1) -\u003e ფანჯარა
alert (a + b);
}
x (1);

ეს arrow აქვს ობიექტი Lexicalenvironment - ეს არის გარეგნობა საგარეო ფარგლებსა და ამ ბმულზე არის დაფუძნებული ქონებით. [] . ასე რომ ობიექტი Lexicalenvironment ჩვენ გვექნება გარე ობიექტის მითითება. ფანჯარა.. როდესაც თარჯიმანი ეძებს ცვლას, მაშინ ის პირველად ეძებს მას ობიექტში Lexicalenvironment, მაშინ, თუ მას არ აღმოაჩნდა ცვლადი, მაშინ გამოიყურება ბმული, გადადის გარე ფარგლებს და ეძებს მას და ასე ბოლომდე. თუ მან ვერ იპოვა ეს ცვლადი სადმე, ეს იქნება შეცდომა. ჩვენს შემთხვევაში, ცვლადი ა. თარჯიმანი ობიექტიდან მიიღებს Lexicalenvironmentდა ცვლადი ბ. ობიექტიდან ფანჯარა.. რა თქმა უნდა, თუ ჩვენ გვაქვს ადგილობრივი ცვლადი ბ. გარკვეული ღირებულებით, ის ჩაიწერება ობიექტში Lexicalenvironment და შემდგომში იქნებიან იქიდან და არა ხილვადობის გარე სფერო.

ᲛᲜᲘᲨᲕᲜᲔᲚᲝᲕᲐᲜᲘ! გახსოვდეთ, რომ ქონება [] იგი დამონტაჟებულია იმ ადგილას, სადაც ფუნქცია გამოცხადდა და არ გამოიწვია, ამიტომ კოდექსის ქვემოთ მოცემულია ნომერი 3 და არა 5, როგორც ზოგი ფიქრობს.

ბარი B \u003d 2;
ფუნქცია x (a) (
alert (a + b);
}

ფუნქცია y ()
v var b \u003d 4;
x (1);
}

ეს იყო ყველა წინასწარმეტყველების მხოლოდ იმის გაგება, თუ როგორ მუშაობს ეს ყველაფერი, და ეს უფრო ადვილი იყო, რომ გაიგოთ, თუ როგორ დახურულია მუშაობა. ახლა ჩვენ პირდაპირ მივმართავთ სტატიის თემას.

როგორც მე ვთქვი, ობიექტი Lexicalenvironment ყოველ ჯერზე განადგურებულია ყოველ ჯერზე ფუნქციის შესრულების შემდეგ და ხელახლა იქმნება. თუმცა, თუ ჩვენ გვინდა ამ მონაცემების შენახვა? ისინი. ჩვენ გვინდა ყველაფერი ჩაწერილი Lexicalenvironment ახლა დაცულია და გამოყენებული იქნა შემდეგი გამოწვევებისთვის? ეს ასეა დახურვა.

ფუნქცია მისალოცი (სახელი) (
// lexicalenenvironment \u003d (სახელი: "ნიკოლაი")
დაბრუნების ფუნქცია () (/ [] \u003d lexicalenvironment
გაფრთხილება (სახელი);
};
}

Var func \u003d მისალოცი ("ნიკოლაი");
მისალოცი \u003d null;
Func ();

მოდი ვნახოთ, რა გავაკეთეთ. პირველი ჩვენ ვქმნით ფუნქციას მისალოცი.რომელშიც სახელი გავიდა. ფუნქცია ქმნის ობიექტს Lexicalenvironmentსადაც ქონება იქმნება (ჩვენი ადგილობრივი ცვლადი) სახელი. და მას ენიჭება სახელი "ნიკოლაი". და ახლა მნიშვნელოვანია: ჩვენ დავბრუნდებით სხვა ფუნქციას ფუნქციისგან, რომელიც შიგნით, რომელიც ჩვენ მივიღებთ გაფრთხილება. ცვალებადი სახელი.. შემდგომ ჩვენ ცვლადს მივცემთ func. ღირებულება დაბრუნდა ფუნქცია მისალოცი.და ეს მნიშვნელობა არის ჩვენი ფუნქცია, რომელიც აჩვენებს სახელს. ახლა ჩვენ მისალოცი. ჩვენ მივცემთ არვენა. ჩვენ უბრალოდ გაანადგურებს ჩვენს ფუნქციას მისალოცი.თუმცა, როდესაც ჩვენ მოვუწოდებთ func.შემდეგ ვნახავთ ცვლადის ღირებულებას სახელი.("ნიკოლაი") ფუნქციები მისალოცი.. როგორ არის შესაძლებელი? და ძალიან მარტივია. საქმე ის არის, რომ ჩვენი დაბრუნებული ფუნქცია ასევე ქონებია. [] რომელიც გულისხმობს ხილვადობის გარე ფარგლებს, და ეს გარე ფარგლებს ჩვენი საქმეა ობიექტი Lexicalenvironment ჩვენი ფუნქცია მისალოცი.. ამიტომ, მიუხედავად იმისა, რომ ჩვენ წაშლა ჩვენი ფუნქცია მისალოცი., საგანი Lexicalenvironment არ წაიშალა და დარჩა მეხსიერებაში, და ის დარჩება მეხსიერებაში, სანამ არ არის მინიმუმ ერთი ბმული. ჩვენ გვაქვს ეს ბმული - ჩვენი დაბრუნებული ფუნქცია, რომელიც ცვლადს იყენებს სახელი. ამ დაწესებულებაში Lexicalenvironment.

ასე რომ, მოდით ახლა მისცეს განმარტება რა არის დახურვა.

წრედი - ფუნქცია ყველა ცვლადთან, რომლებიც ხელმისაწვდომია.

ისე, სტატია აღმოჩნდა საკმაოდ მოცულობითი, მაგრამ ეს მხოლოდ იმიტომ, რომ მე შევეცადე აღწერს მთელი პროცესი დახურვის. კონსოლიდაცია, მინდა, რომ მარტივი მაგალითია - მეტრი გამოყენებით თემის გამოყენებით შესწავლილი. გთხოვთ გაუმკლავდეთ კოდს და დაწერეთ კომენტარებში, როგორ და რატომ მუშაობს. თუ არ გესმის რაღაც, თქვენ ასევე შეგიძლიათ სთხოვოთ შეკითხვას. Მადლობა ყურადღებისთვის!

ფუნქცია Makecounter ()
var currentcount \u003d 0;

დაბრუნების ფუნქცია ()
CURRENTCOUNT ++;
დაბრუნების მიმდინარეობა;
};
}

Var counter \u003d makecounter ();
Counter ();
Counter ();
Alert (counter ()); // 3.

-ში JavaScript ფუნქციები შეიძლება აღინიშნოს არა მხოლოდ ერთი მიყოლებით, არამედ ერთი შიგნით. როდესაც თქვენ გაქვთ ერთი ფუნქცია შიგნით სხვა, შიდა poundation აქვს წვდომა ალტერნატიული გარე ფუნქცია.

ფუნქცია გარე (x) (var tmp \u003d 3; ფუნქცია შიდა (y) (alert (x + y + ++ tmp)); / ხსნის 16) შიდა (10);) გარე (2);

ეს კოდი ყოველთვის აძლევს 16-ს, რადგან შიდა ფუნქცია ხედავს X- ს, რომელიც არის ცვლადი funkuction გარე. -ში ეს საქმე არგუმენტის ფუნქცია. ასევე შიდა () შეგიძლიათ იხილოთ TMP გარედან ().

ეს ეწოდება დახურვას ან დახურვას. თუ უფრო ზუსტად, დახურვის ეწოდება გარე ფუნქცია, და ყველაფერი შიგნით მას უწოდებენ დახურვის გარემოს ან დახურვის გარემო.

ხანდახან ნათქვამია, რომ დახურვა ფუნქცია, რომელიც დააბრუნებს ფუნქციას, ეს არასწორია, რათა დაასახელოს დახურვის ფუნქცია, რომ შიდა ფუნქცია ვრცელდება ცვლადს მის ფარგლებს გარეთ.

ფუნქცია foo (x) (var tmp \u003d 3; დაბრუნების ფუნქცია (y) (alert (x + y + ++ tmp)); // ასევე გააფრთხილა 16)) var bar \u003d foo (2); / / ბარი არის დახურვა. ბარი (10);

ზემოაღნიშნული ფუნქცია ასევე აჩვენებს 16-ს, რადგან ბარის შემდეგაც კი დასრულდა X და TMP- ის წვდომა, მაშინაც კი, თუ ბარი ცვლადი არ არის შიგნით ფარგლებში, სადაც ისინი გამოცხადდნენ.

ამავე დროს, მას შემდეგ, რაც TMP ცვლადი ჯერ კიდევ შიგნით ბარი დახურვა, იგი აგრძელებს გაზრდის ყოველ ჯერზე ბარი ზარი.

Აქ მარტივი მაგალითი Circuit:

Var \u003d 10; ფუნქციის ტესტი (console.log (a); / დასკვნა 10 console.log (b); / დასკვნა 6) var b \u003d 6; ტესტი ();

JavaScript- ში ფუნქციის დაწყებისას, გარემოზე შექმნილია, ანუ, ეს არის ყველა ცვლადი სიაში, არა მხოლოდ არგუმენტები და ცვლადები მასში, არამედ გარეთ, ამ მაგალითში არის " "და" ბ ".

თქვენ შეგიძლიათ შექმნათ ერთზე მეტი დახურვის ერთ გარემოში, დაბრუნების მასივი, ობიექტი ან მიმაგრებული გლობალური ცვლადი. ამ შემთხვევაში, ისინი ყველაფერს აკეთებენ იგივე X ან tmp ღირებულება ინდივიდუალური ასლების შექმნის გარეშე.

ჩვენი მაგალითიდან X არის ნომერი, მაშინ მისი ღირებულება კოპირება Foo როგორც მისი არგუმენტი x.

მეორეს მხრივ, JavaScript ყოველთვის იყენებს კავშირებს, როდესაც ობიექტები გადაცემულია. თუ თქვენ მოუწოდებთ foo ობიექტს, როგორც არგუმენტი, მაშინ დაბრუნების დახურვა დაბრუნდება ბმული ორიგინალური ობიექტი!

ფუნქცია foo (x) (var tmp \u003d 3; დაბრუნების ფუნქცია (y) (alert (x + y + tmp); x.memb \u003d x.memb? X.memb + 1: 1; alert (x.memb);) ) Var Age \u003d ნომერი (2); var bar \u003d foo (ასაკი); / / ბარი არის დახურვის ასაკში. ბარი (10);

როგორც მოსალოდნელი იყო, თითოეული ზარის ბარი (10) იზრდება x.memb. რა შეიძლება ველოდოთ, ასე რომ x აგრძელებს იმავე ობიექტს, როგორც ასაკს! მას შემდეგ, რაც ორი ზარის ბარი, ასაკი. Memb იქნება 2! სხვათა შორის, მეხსიერების გაჟონვის HTML ობიექტების მოხდეს.

პროგრამირების, დახურვის ან ინგლისურენოვანი ვერსია "დახურვა" არის პირველი კლასის ფუნქციების კონტექსტური სავალდებულო სახელის დანერგვის მეთოდი. ოპერატიულად, ეს არის ჩანაწერი, რომელიც ინახავს ფუნქციას ერთად საშუალო. გარემო თითოეული უფასო ფუნქციის შედარებაა ღირებულებით ან მითითებით, რომელსაც უწოდებენ JavaScript- ის დახურვას. იგი საშუალებას აძლევს ხელმისაწვდომობის წვდომას ცვლადების მეშვეობით ასლები ღირებულებების ან ბმულები, მაშინაც კი, როდესაც გამოიწვია გარეთ რეგიონში.

კონცეფცია დახურვის

1960-იან წლებში 1960-იანი წლების დახურვა შემუშავდა 1970 წელს გამოვლენილი გამონათქვამების მექანიკური შეფასებისათვის, როგორც პალპროგრამის ენის ფუნქცია, რომელიც მხარს უჭერს პირველი კლასის ფუნქციებს ლექსიკურ სფეროსთან. პიტერ ლანნმა 1964 წელს ტერმინი "დახურვა" განსაზღვრავს.

ასეთი ახსნა შედის 1975 წელს, როგორც ლექსიკურად შეზღუდული ლიუსის ვერსია და ფართოდ გავრცელდა. ლექსიკური გარემო არის პროგრამის მრავალფეროვანი ცვლადები. იგი შედგება შიდა ლექსიკური საშუალო და გარე გარემოს მითითება, რომელსაც უწოდებენ არალოკალური ცვლადები.

ლექსიკური დახურვა JavaScript- ში არის გარე გარემოებით. როგორც JavaScript- ში, ყველა ცვლადს აქვს ბმული ტიპი. JS იყენებს მხოლოდ სავალდებულო მითითებას - რომელიც შეესაბამება C ++ 11- ს, ხოლო ფუნქციის მიერ დაკავებული არასაკმარისი ცვლადების სიცოცხლეში გადანაწილებულია ფუნქციის სიცოცხლეში.

JavaScript- ში სქემები ჩვეულებრივ გამოჩნდება პირველ კლასში. ასეთი ენები საშუალებას გაძლევთ გადავიტანოთ ფუნქციები, როგორც არგუმენტები. და ასევე დაბრუნდება ფუნქცია ზარები და მიამაგრეთ ცვლადი სახელები. ეს ხდება მარტივი ტიპების მსგავსად, როგორიცაა სიმები და რიცხვები.

ამ მაგალითში Lambda Expression (Lambda (\u003e \u003d (წიგნის გაყიდვების წიგნი) ბარიერი) გამოჩნდება საუკეთესო გაყიდვადი წიგნების ფუნქციაში. როდესაც Lambda გამოხატვის გამოითვლება, Circuit ქმნის დახურვას, რომელიც შედგება კოდის გამოხატვისათვის Lambda- ს გამოხატვისა და ბარიერის ცვლადის მითითებაზე, რომელიც არის Lambda გამოხატვის ფარგლებში თავისუფალი ცვლადი. დახურვა მაშინ გადადის ფილტრის ფუნქციით, რომელიც იწვევს მას არაერთხელ, რათა დადგინდეს, თუ რომელი წიგნები უნდა დაემატოს შედეგების სიას და რომელიც უნდა გაუქმდეს.

მას შემდეგ, რაც ბარიერის ღირებულების დახურვა, ამ უკანასკნელს შეუძლია გამოიყენოს იგი ყოველ ჯერზე მისი ფილტრის მიზეზით. ფილტრის ფუნქცია თავად შეიძლება განისაზღვროს სრულყოფილად ცალკე ფაილი. აქ არის იგივე მაგალითი, გადაწერილი JS- ში. იგი გვიჩვენებს, თუ როგორ დახურვა ქვეშ hood ქვეშ JavaScript მუშაობა.

სიტყვით აქ არის გამოყენებული გლობალური ფილტრის ფუნქციის ნაცვლად, მაგრამ დანარჩენი სტრუქტურა და კოდექსის ეფექტი იგივეა. ფუნქცია შეუძლია შექმნას უფრო ახლოს და დავუბრუნდეთ მას, რადგან ეს ამ შემთხვევაში განიცდის ფუნქციის შესრულებას ცვლადებს F და DX- ს განაგრძობს წარმოების შემდეგ, მაშინაც კი, თუ აღსრულება დატოვებს მათ ფარგლებს და ისინი აღარ ჩანს.

ენებზე, დახურვის გარეშე, ავტომატური ლოკალური ცვლადის სიცოცხლე ემთხვევა დასტის ჩარჩოს შესრულებას, სადაც ეს ცვლადი გამოცხადდა. JavaScript- თან, IIEF- ის დახურვასა და ფუნქციებს, ცვლადები უნდა გაგრძელდეს, სანამ არ არსებობს არსებული საკეტები მათთვის ცნობას. ეს ყველაზე ხშირად ხორციელდება ნაგვის შეგროვების ზოგიერთი ფორმის გამოყენებით.

დახურვის უპირატესობა ისაა, რომ ის ინარჩუნებს ფარგლებს, გარე ან "მშობლის" კონტექსტის "ხილვადობის ჯაჭვის". ასეთი ქცევა შეიძლება გამოყენებულ იქნას რამდენიმე გზით და გახდა სასარგებლო ინსტრუმენტი, რათა თავიდან იქნას აცილებული სხვადასხვა JavaScript შეცდომების თავიდან ასაცილებლად. ერთ-ერთი ყველაზე გავრცელებული პრობლემაა "მარყუჟების" პრობლემა.

ციკლის პრობლემა ხდება მაშინ, როდესაც მომხმარებელი ქმნის ფუნქციას ციკლში და ელოდება ცვლადის ამჟამინდელ ღირებულებას ახალი ფუნქციამაშინაც კი, თუ ცვლილებები Cycles კონტექსტში ახალი ფუნქციის დარეკვით. ამგვარად გამოყენებული დახურვა აღარ აქვს მინიშნება გამჭვირვალობა და, აქედან გამომდინარე, აღარ არის სუფთა ფუნქციები, თუმცა ისინი საყოველთაოდ გამოიყენება უწმინდურ ფუნქციურ ენებზე, როგორიცაა სქემა. იმისათვის, რომ გავიგოთ, რა არის დახურვის JavaScript, თქვენ უნდა განიხილოს გამოყენების შემთხვევაში. სინამდვილეში, პრაქტიკაში, მათ აქვთ ბევრი პროგრამა:

  1. ისინი შეიძლება გამოყენებულ იქნას კონტროლის სტრუქტურების დასადგენად. მაგალითად, ყველა სტანდარტული Smalltalk მართვის სტრუქტურები, მათ შორის ფილიალები (თუ / შემდეგ / სხვა) და ციკლები (ხოლო და ამისთვის), განისაზღვრება ობიექტების გამოყენებით, რომელთა მეთოდები დაიხურება. მომხმარებელს შეუძლია ასევე ადვილად გამოიყენოს დახურვა კონტროლის სტრუქტურის დასადგენად. ენებზე, რომლებიც მიზნად ისახავს, \u200b\u200bთქვენ შეგიძლიათ შექმნათ მისი მრავალფუნქციური საშუალო, რაც საშუალებას გაძლევთ კონფიდენციალურად კომუნიკაციურად და შეცვალონ ეს გარემო. დახურვა გამოიყენება ობიექტის სისტემების შესაქმნელად.
  2. შექმნის ორივე კერძო და საჯარო ცვლადი მეთოდები მოდულის თარგების გამოყენებით. იმის გამო, რომ დაბრუნებული თვისებები მემკვიდრეობის ფართობი მშობლის ფუნქცია, ისინი ხელმისაწვდომია ყველა ცვლადი და არგუმენტები ამ კონტექსტში.
  3. ეს არის სასარგებლო სიტუაცია, როდესაც ფუნქცია იყენებს იმავე რესურსს თითოეული ზარისთვის, არამედ ქმნის რესურსს. ეს გარემოება ხდის მეთოდს არაეფექტურია, რომელიც მხოლოდ დახურვის გზით არის აღმოფხვრილი.

MDN- ის (Mozilla Developer Network) ინფორმაციით, "დახურვა ფუნქციონირებს დამოუკიდებელ ცვლადებთან, რომ" გახსოვდეთ "მისი შექმნის გარემო". და, როგორც წესი, როდესაც ფუნქცია დასრულდა, მისი ადგილობრივი ცვლადები აღარ არსებობს. გაითვალისწინეთ, თუ როგორ დახურეთ JavaScript სამუშაოები, შეგიძლიათ განიხილონ რამდენიმე მექანიზმი. პირველი ფორმალური ლოგიკაა. მაგალითად, ჟურნალის ფუნქციის გამოყენება, რომელიც ერთი სახელია, როგორც პარამეტრი და რეგისტრირებულია. შემდეგ შევქმენით ციკლისთვის სახელების სიაში, დააყენეთ 1-ჯერ, და შემდეგ მოვუწოდებთ ჟურნალის ფუნქციას მიმდინარე სახელით.

პირველ კლასში ენაზე, შეგიძლიათ მანიპულირება ისევე, როგორც სხვა ტიპის მონაცემები, როგორიცაა int ან string. მხოლოდ ეს მექანიზმი საშუალებას აძლევს ბევრს შექმნას წარმოუდგენელი რამ, მაგალითად, ცვლადი ფუნქციის მინიჭება ან სხვა ფუნქციის პარამეტრის გადასასვლელად.

ეს პრინციპი გამოიყენება მრავალი სტრუქტურით, ისევე როგორც DOM მოვლენების დამლაგებლები. პირველი, ღონისძიება არის "მოსმენა", შემდეგ დაავალოს Callback ფუნქცია, რომ მოუწოდა ყოველ ჯერზე მოვლენა გამოიწვია.

ანონიმური ფუნქცია ფუნქციაა სახელით. პრაქტიკულად ახალბედა პროგრამისტები მათ ყოველდღიურად აკმაყოფილებენ თამაშს. მაგალითად, განახორციელოს დამატებით ოპერაცია, შეგიძლიათ გაიაროთ ცვლადები, მაგალითად:

  • var x \u003d 3;
  • y \u003d 5;
  • var z \u003d x + y.

ან თუ არ აპირებთ ხელახლა პროცესის ნომრებს: v v \u003d 3 + 5;

ეს არის ანონიმური ოთახები. ანონიმური ფუნქციებისთვის, შეგიძლიათ გამოაცხადოთ ისინი, როდესაც ისინი "ფრენაზე" იყენებენ - ცვლადის გარეშე. მაგალითად, მიიღეთ ფუნქცია ადრე ადრე:

(Alert ("Ceci არის Une Fonchan Anonyme");

უფრო მეტიც, არსებობს ალტერნატიული სინტაქსი, რომელიც ხაზს უსვამს ფუნქციის დეკლარაციას, რომელიც ხაზს უსვამს, რომ ორივე ფუნქცია შეიძლება იყოს ანონიმური და მარტივი ცვლადების მიმართ, რაც ხელსაყრელი ფუნქციის დამონტაჟების მოსახერხებელია.

სინამდვილეში, ეს არის იგივე მექანიზმი, მაგრამ ამ თვალსაზრისით ეს საშუალებას მოგცემთ დაინახონ, თუ როგორ ფუნქციას დახურულია შიგნიდან. როგორც ჩანს, მას შემდეგ, რაც ფუნქციები ცვლადებია, როგორც სხვები, არ არსებობს მიზეზი, რისთვისაც ისინი არ შეიძლება განისაზღვროს ადგილობრივად. ნულოვანი მიზნით, როგორიცაა C, C ++ და Java, ყველა ფუნქცია განისაზღვრება ერთ დონეზე ხილვადობის, იმავე კლასში ან გლობალურ დონეზე. მეორეს მხრივ, JavaScript- ში, ადგილობრივი ფუნქცია ქრება, ისევე როგორც სხვა ადგილობრივი ცვლადები, როგორც კი მშობლის ფუნქცია მთავრდება, ამიტომ სხვა ფუნქციებისგან არ ჩანს.

ეს მართლაც რთულია, მაგრამ JavaScript- ს აქვს გზა, რომელიც აკონტროლებს ცვლადების ხილვადობას და ორ გზასც კი. JavaScript- ში გლობალური ცვლადის მინიჭება იგივე მექანიზმია, როგორც Java - კომპლექსური ობიექტები, მასივები, დომების ელემენტები და სხვები გადაცემულია მითითებით, ასე რომ შემდეგ კოდექსში:

var tab \u003d; Var tab2 \u003d tab.

სად, tab და tab2 არის ორი ბმული იგივე მაგიდაზე, ტექნიკურად ეს არის მაჩვენებლები კონტროლირებადი ნაგვის კოლექციონერი. ფუნქციები ასევე გადაცემულია მითითებით. Globalfn ცვლადი აღარ არის დაფარული. ბრძანება საშუალებას გაძლევთ გააკეთოთ ის, რაც აჩვენებს JavaScript- ის დახურვის მაგალითს.

ეს არის ის, თუ როგორ შეგიძლიათ ამონაწერი ფუნქცია ადგილობრივი კონტექსტიდან, თუ ფუნქცია აკმაყოფილებს სხვა ადგილობრივ ცვლადებს. მარტივი მაგალითი: ავტომატური გაზრდა, ფუნქცია, რომელიც დააბრუნებს რიცხვს, რომელიც იზრდება 1 ყოველ ჯერზე ზარი. კერძოდ, Inc ფუნქციის საჭიროებები, რომელიც იქცევა შემდეგნაირად:

// Retourne 0 Inc ();

// Retourne 1 Inc ();

// Retourne 2 Inc ();

დახურვისთვის ჰგავს:

ფუნქცია Makeinc () (var x \u003d 0; დაბრუნების ფუნქცია () (დაბრუნება x ++;)) var inc \u003d makeinc ();

უკანასკნელ რიგში იმ მომენტში, როდესაც INC ცვლადი შეიქმნა, იგი ახორციელებს გარკვეულ ცვლადებს, რომლებიც გარშემო, ამ შემთხვევაში x. იგი ქმნის გარკვეულ უხილავი ობიექტის ფუნქციას, რომელიც შეიცავს ამ ცვლადს. ეს ობიექტი არის JavaScript დახურვის ფუნქცია. ამავდროულად, ფუნქციის თითოეული ასლი ექნება საკუთარ დახურვას:

var inc1 \u003d makeinc ();

var inc2 \u003d makeinc ();

როგორც ჩანს, დახურვა ძალიან სასარგებლოა ხშირ შემთხვევაში.

ცვლადი სახელის კონფლიქტების თავიდან ასაცილებლად, სახელთა სივრცე ჩვეულებრივ გამოიყენება. JavaScript- ში, სახელთა სივრცეები, როგორც სხვა.

ბუნებრივია, A.x და B.X არ არის იგივე ცვლადი. თუმცა, თუ თქვენ უბრალოდ უნდა დაიწყოს სკრიპტი, არ მოითხოვს გადარჩენის ცვლადების დანარჩენი, ანონიმური ფუნქცია შეიძლება გამოყენებულ იქნას, როგორც დახურვა. ეს აძლევს ოდნავ უცნაურ სინტაქსს. მიუხედავად იმისა, რომ ორი კოდები შუა საკმაოდ ხშირია, მეორეს მხრივ, ფუნქცია, რომელიც გარშემო არის შესრულებული "on fly". ყურადღება მიაქციეთ ფრჩხილებს () დასასრულს. და შეძლებს დახურვის, ანონიმური ფუნქცია თავად უნდა იყოს გარშემორტყმული მრგვალი ფრჩხილებით.

ამ ანონიმურ ფუნქციაში გამოიყენეთ ადგილობრივი ცვლადი, პუნქტი. ეს არის დიდი გზა, რათა თავიდან იქნას აცილებული სახელი კონფლიქტები ან შეშფოთება, არამედ წინააღმდეგ ataks XSS. საბაჟო ცვლადები დაცულია, ვერავინ შეცვლის მათ, რათა გავლენა მოახდინოს სკრიპტის ქცევაზე.

არსებობს ვარიანტი: (ფუნქცია () (// ...) ());

ამავე დროს ყურადღება მიაქციეთ ფრჩხილების ნებართვას. განსხვავება ამ ორ ვარიანტს შორის საკმაოდ რთულია იმის ახსნა, რადგან ისინი დაკავშირებულია იმასთან დაკავშირებით, თუ როგორ ხდება კოდი ლექსიკური ანალიზატორი. ორივე შემთხვევაში, ფუნქცია ითვლება გამოხატულებად, მაგრამ ეს გამოხატულება ერთდროულად არ არის შეფასებული. უბრალოდ უნდა გვახსოვდეს, რომ ის იღებს ორ წყვილს მრგვალი ფრჩხილების: ერთი ფუნქცია და ერთი უკან.

JavaScript პროგრამირების ციკლები

როდესაც მომხმარებელი ასრულებს JavaScript პროგრამირების დიდ მოცულობას, ძნელია, რათა თავიდან იქნას აცილებული ციკლის თავიდან ასაცილებლად. ვინმეს გიჟურია, რის შემდეგაც ისინი იდეას მიდიან, რომ JavaScript- ის ნებისმიერი განხორციელება სერიოზული შეცდომაა. იმ შემთხვევაში, თუ დეველოპერი უკვე აქვს ციკლი, რომ მას არ სურს გარდაქმნას გამოიყენოს ფუნქცია iterator, ყველაფერი, რაც მას სჭირდება, არის დახურვა, რომელშიც ის განსაზღვრავს ახალ ცვლადებს. ისინი აფიქსირებენ მიმდინარე ღირებულებას ცვლადების და თითოეული iteration- ზე. ცვლადების გადაღებისას ის არის, რომ გარე დახურვა დაუყოვნებლივ შესრულდება ციკლის ამჟამინდელ აქტარში. თქვენ შეგიძლიათ გამოიყენოთ ერთ-ერთი ასეთი ორი სავარაუდო მიდგომა.

ახლა ამ პრობლემის კიდევ ერთი გამარტივებული გამოსავალია, მას შემდეგ, რაც საკვანძო სიტყვა მხარს უჭერს როგორც Firefox- ში და Chrome- ში. Ეს არის სიტყვა ნაცვლად var ცვლადი ბლოკი. მოდით კარგად მუშაობს, რადგან ახალი ცვლადი J გამოცხადებულია, რომელთა ღირებულებაც ციკლის შიგნით დახურვისას დაფიქსირდა. თუმცა, უნდა გაითვალისწინოს, რომ ის არ განაგრძობს ციკლის იმავე გაერთიანების დასრულების შემდეგ, რადგან ადგილობრივად არის.

Loop და ფუნქცია

JavaScript- ში მარყუჟისთვის არ ჩანს, ასევე ციკლისთვის C ან Java- ში. სინამდვილეში, ეს უფრო მეტად გამოიყურება PHP- ს. ყველაზე მნიშვნელოვანი ცოდნა Cycles in JS არის ის, რომ ისინი არ ქმნიან ფართობი. JS არ აქვს სფეროს ბლოკი, მხოლოდ მოცულობის ფუნქცია. ეს ქონება შეიძლება ჩაითვალოს შემდეგ ფრაგმენტზე:

ფუნქცია foo () (var bar \u003d 1;

for (var i \u003d 0; მე< 42; i++) {var baz = i;} /* more code */}

ნათელია, რომ ბარი ხელმისაწვდომია მთელ ფუნქციაში. BAZ ციკლის პირველი iteration- ის დაწყებამდე განუსაზღვრელი იქნება. ციკლის შემდეგ, მას ექნება 41 (და 42 წლის იქნება). ამდენად, ნებისმიერი ცვლადი გამოაცხადა ფუნქცია ნებისმიერ ფუნქციაში ხელმისაწვდომი იქნება ყველა ფუნქციაში და მხოლოდ ძალაშია მას შემდეგ, რაც მას დაინიშნა.

საკეტები და აგრეგაცია

დახურვა სხვა არაფერია, ვიდრე ფუნქციები, სხვა ფუნქციებში, და სხვა კონტექსტში გადადის. ისინი უწოდებენ დახურვას, რადგან ისინი ადგილობრივ ცვლადებს დახურეს, რაც ხელმისაწვდომია სფეროს სხვა სფეროებში. მაგალითად, დრო, X განსაზღვრული, როგორც foo პარამეტრი, და Var Bar \u003d foo (2) () დაბრუნდება 84.

დაბრუნებული Foo ფუნქცია აქვს წვდომა x. ეს ყველაფერი მნიშვნელოვანია, რადგან ის ეხმარება დეველოპერებს, რათა შეიქმნას ფუნქციები ციკლის ცვლადებზე. განვიხილოთ ეს ფრაგმენტი, რომელიც დააკმაყოფილებს პროცესორს სხვადასხვა ელემენტებს:

// ელემენტები არის 3 DOM ელემენტების მასივი Var Values \u200b\u200b\u003d ["Foo", "ბარი", "ბაზი"];

ᲛᲔ.< l; i++) {var data = values[i];

ელემენტები [i] .ONClick \u003d ფუნქცია () (გაფრთხილება (მონაცემები);

ღირებულება ისინი გამოიყენებს მზადყოფნაში, როდესაც დაჭერით, იქნება იგივე ყველასთვის, კერძოდ Baz. იმ დროს, ღონისძიების დამმუშავებელი ეწოდება, უკვე დასრულებულია. JS არ გააჩნია ბლოკი ფართობი, ანუ. ყველა handlers გამოიყენოთ ბმული იგივე მონაცემების ცვლადი. მარყუჟის შემდეგ, ეს მნიშვნელობა იქნება ღირებულებები. თითოეული ცვლადი დეკლარაცია ქმნის ერთ ადგილს შენახვის მეხსიერებაში. ამ მონაცემებით, ეს მონაცემები კვლავ შეიცვალა და ისევ, მეხსიერების პოზიცია უცვლელი რჩება.

თითოეული ღონისძიება Handler აქვს ხელმისაწვდომობის იგივე პოზიცია მეხსიერებაში. ერთადერთი გამოსავალი არის კიდევ ერთი ფართობი, რომელიც "აფიქსირებს" მიმდინარე მონაცემთა ღირებულებას. JS- ს აქვს მხოლოდ სპექტრი ფუნქციები. აქედან გამომდინარე, სხვა ფუნქცია შევიდა. მაგალითი:

ფუნქცია CreateEventhandler (X) (დაბრუნების ფუნქცია () (alert (x);

(var i \u003d 0, l \u003d elethents.length;

ᲛᲔ.< l; i++) {var data = values[i];

ელემენტები [i] .ONClick \u003d CreateEventhandler (მონაცემები);

იგი მუშაობს, რადგან მონაცემთა ღირებულება ინახება ადგილობრივ ტერიტორიაზე, CreateEventhandler და ეს ფუნქცია ხორციელდება თითოეულ iteration. მოკლედ შეიძლება დაწერილი იყოს შესრულებული ფუნქციების გამოყენებით:

(var i \u003d 0, l \u003d elethents.length;

ᲛᲔ.< l; i++) {var data = values[i];

ელემენტები [i] .ONClick \u003d (ფუნქცია (x) (ფუნქცია () (alert (x);

JavaScript- ში დახურვის პრაქტიკული მაგალითი

თუ მომხმარებელი ბრაუზერში კოდექსის ზემოთ მოყვება, შეიძლება პრობლემის გაცნობა, რადგან მას შეუძლია სინტაქსის შეცდომა. თუ იგი ახორციელებს კოდს პირდაპირ ბრაუზერში, შანსი ძალიან მაღალია, არ შედგენა webpack შედგენის პროცესში. შესაძლო გადაწყვეტილებები:

ფუნქციის მუშაობა (სახელი) (

დაბრუნების ფუნქცია (თემა) (

console.log (რა არის $ (თემა) $ (სახელი));

მუშაობა ("JavaScript") ("დახურვა");

პირველი, ფუნქცია ეწოდება და სახელი არგუმენტი გადაცემულია. ახლა ეს ფუნქცია ლექსიკა ასევე დააბრუნებს ფუნქციას, რომელიც ასევე იღებს თემების არგუმენტს. ეს ფუნქცია გამოდის გამომავალზე და გამომავალი აქვს ცვლადს.

Insider ფუნქციები ფართობი არ შემოიფარგლება ამ ფუნქცია, ამიტომ კონცეფცია ეწოდება დახურვის, რადგან მას აქვს ამ სფეროში გარე პარამეტრი. დაბრუნებულ ფუნქციას აქვს გარე ლექსიკური არეალის ან კონტექსტის ხელმისაწვდომობა. როდესაც დეველოპერი მოუწოდებს ფუნქციას, რომელიც ასევე დააბრუნებს მას, მაშინ პირველად მოუწოდა ცვლადი ფუნქცია ყოველთვის ხელმისაწვდომია შიდა ფუნქციით. შემდგომი მაგალითი შემდეგი კოდით.

შიდა ფუნქციის მაგალითი

დაწვრილებით JavaScript- ში დახურვის შესახებ მეორე მაგალითზე. ახლა ეს შესრულების გარემო განადგურებულია, მაგრამ პარამეტრის სახელი ჯერ კიდევ არსებობს. შექმნილია ახალი შიდა ფუნქციური საშუალება, რომელიც არის ანონიმური ფუნქცია. მას აქვს გარე ლექსიკური გარემოს ფართობი.

ამრიგად, გარე გარემოს ცვლადში ის ჯერ კიდევ არსებობს, რომ ანონიმურ ფუნქციას აქვს კონსოლში სახელის ცვლადი ნამუშევრები, მაგალითად, "რა არის JavaScript- ში დახურვა". შიდა ანონიმური ფუნქცია //main.js

ფუნქციის ქარხანა () (var products \u003d;

i ++) (PRODUCTS.PUSH (ფუნქცია () (Console.log (I);

) დაბრუნების პროდუქტები;

) Var Soap \u003d ქარხანა ();

ამ მაგალითის შედეგი საკმაოდ უმნიშვნელოა და 2 ტოლია.

როდესაც საპნის არის საპნის () მოუწოდა გარე კონტექსტში ცვლადი, ყოველთვის 2, რადგან ციკლის მდგომარეობა არის FALSE I<2, поэтому при этом значение i равно 2, а во время вызова нужно напечатать значение в консоль так, она всегда пишет 2. То же самое для мыла - soap ().

ფუნქციების შექმნა "ფრენაზე"

თქვენ შეგიძლიათ შექმნათ ფუნქციები ქარხანა - ფუნქციონალური, რომელიც ასრულებს საბაჟო ამოცანებს. ფუნქციის ფუნქცია ფუნქციების ქარხნიდან იქნება დახურვის, შენახვის საშუალება.

var FunctionFactory \u003d ფუნქცია (NUM1) (დაბრუნება Num1 * Num2;

ზემოთ მოცემულია ერთი ფუნქციონალური ნომრის გადაცემა. შემდეგ ფუნქციონირებს დახურვის დახურვა, გავიხსენოთ NUM1 მნიშვნელობა. შედეგად ფუნქცია მიზნად ისახავს ორიგინალური Num1 ჯერ Num2- ის ღირებულებას, რომელიც გადადის, როდესაც მოუწოდა.

var mult5 \u003d ფუნქციონალური (5);

var mult10 \u003d ფუნქციონალური (10);

ზემოთ მხოლოდ Mult5 და Mult10 ფუნქციები ქმნის. ახლა თქვენ შეგიძლიათ მიმართოთ რომელიმე ამ ფუნქციას ახალი ნომრის გავლით 5 ან 10-ით. ახლა ხედავთ შედეგს.

დახურვა არის ერთ-ერთი ყველაზე ძლიერი JavaScript ფუნქცია, მაგრამ ეს არ შეიძლება გამოყენებულ იქნას სწორად გაგება არსი. ისინი შედარებით ადვილია შანსი, რომ ეს არის საშიში დახურვის JavaScript. მათი შექმნის პოტენციურად მავნე ეფექტები, განსაკუთრებით შედარებით საერთო ვებ ბრაუზერის გარემოში. უარყოფითი შეჯახების თავიდან ასაცილებლად უარყოფითი მხარეები და ისარგებლეთ უპირატესობებით, რომ მათ სთავაზობენ, აუცილებელია მათი მექანიზმის გაგება.

ამ სტატიაში მე შევეცდები, რომ ახსნას JavaScript- ში ხილვადობისა და დახურვის სფერო, რომელშიც ბევრი გამოცდილება სირთულეებს.

შესავალი

არსებობს რამდენიმე სტატია ქსელში, რომლებიც ცდილობენ ახსნას ხილვადობისა და დახურვის სფეროები, მაგრამ ზოგადად, მე ვიტყოდი, რომ მათი უმრავლესობა არ არის სრულიად გასაგები. გარდა ამისა, ზოგიერთ სტატიაში ვარაუდობენ, რომ თქვენ პროგრამას 15 სხვა ენაზე, თუმცა, ვფიქრობ, JavaScript- ზე წერა მხოლოდ HTML და CSS- ში, და არა C ან Java- ში.

აქედან გამომდინარე, ამ სტატიის მიზანია ახსნას ყველა - რა არის ხილვადობის ფარგლები და დახურვა, როგორც ისინი მუშაობენ, და რაც მთავარია, რა უპირატესობაა. ამ სტატიის წაკითხვის დაწყებამდე თქვენ უნდა იცოდეთ ძირითადი ცნებები ცვლადების და ფუნქციების შესახებ JavaScript- ში.

ხილვადობის ფართობი

ფარგლებს ნიშნავს, რომ ცვლადები და ფუნქციები ხელმისაწვდომია და რომელი კონტექსტში ისინი შესრულებულია. ცვლადი ან ფუნქცია შეიძლება განისაზღვროს გლობალურ ან ადგილობრივ სფეროში ხილვადობის სფეროში. ცვლადებს აქვთ ფუნქციის ხილვადობის ე.წ. ფუნქცია, ხოლო ფუნქციებს აქვთ იგივე ფარგლები, როგორც ცვლადები.

გლობალური ფარგლები

როდესაც რამე გლობალურია, ეს იმას ნიშნავს, რომ ეს თქვენს კოდექსში არსად არის შესაძლებელი. განვიხილოთ მაგალითი:

var monkey \u003d "გორილა"; ფუნქცია GreetVisitor () (დაბრუნების Alert ("Hello Dear Blog Reader!");)

თუ ეს კოდი შესრულდა ვებ-ბრაუზერში, მაშინ ხილვადობის არეალი იქნება ფანჯარა, რომელიც ხელმისაწვდომი იქნება ფანჯარაში ყველაფრისთვის.

ადგილობრივი მასშტაბი

გლობალური ხილვადობისგან განსხვავებით, ადგილობრივი ხილვადობაა, როდესაც რაღაც განისაზღვრება და მხოლოდ კოდექსის ზოგიერთ ნაწილში, როგორიცაა ფუნქცია. განვიხილოთ მაგალითი:

ფუნქცია Talkdirty () (Var Saide \u003d "Oh, თქვენ პატარა VB Lover, თქვენ", დაბრუნების მზადყოფნაში (ამბობდა);) alert (ამბობდა); // დააგდეს შეცდომა

ამ მაგალითში, სიტყვის ცვლადი ხელმისაწვდომია მხოლოდ საკონცერტო ფუნქციის შიგნით, რომელიც არ არის განსაზღვრული. შენიშვნა: თუ თქვენ გამოვლინდა სიტყვით სიტყვით, ავტომატურად გახდება გლობალური.

გარდა ამისა, თუ თქვენ გაქვთ წყობილი ფუნქციები, შიდა ფუნქცია ექნება ხელმისაწვდომს ფუნქციებს, რომელშიც იგი ჩართულია, ასევე ცვლადები:

ფუნქცია Capitalizename (დაბრუნება FirstName.Tuppercascase ();) Var Capitalized \u003d Capitalizename (); დაბრუნება კაპიტალიზაცია;) alert (savename ("რობერტ")); / / ბრუნდება "რობერტ"

როგორც დაინახეთ, შიდა ფუნქციის კაპიტალიზენამს არ სჭირდება ნებისმიერი პარამეტრების გადაცემა, რადგან მას აქვს სრული ხელმისაწვდომობის პირველი სახელი პარამეტრების გარე ფუნქცია Savename. უფრო მეტი სიცხადე, განიხილეთ კიდევ ერთი მაგალითი:

ფუნქცია ძმა ("იოანე", "ლიზა", "პეტრე"]; ფუნქცია SiblingCount () (var siblingslength \u003d siblings.length; დაბრუნება SiblingsLength;) ფუნქცია joinsiblingnames () (დაბრუნება "მე მაქვს" + SiblingCount () + "ძმათა: NN" + ძმები.ჯოინი ("ნ");) დაბრუნების joinsiblingnames ();) alert (ძმები ()); // შედეგები "მე მაქვს 3 ძმა: ჯონ ლიზა პეტრე"

როგორც ხედავთ, ორივე შიდა ფუნქციას აქვს ძმათა მასივის ხელმისაწვდომობა, ხოლო თითოეულ შიდა ფუნქციას აქვს იმავე დონის სხვა შიდა ფუნქციის ხელმისაწვდომობა (ამ შემთხვევაში, Joinsiblingnames- ს აქვს SiblingCount- ის ხელმისაწვდომობა). თუმცა, SiblingsLengenth ცვლადი შიგნით SiblingCount მხოლოდ ამ ფუნქციის შიგნით არის შესაძლებელი, I.E. ამ სფეროში ხილვადობა.

წრედი

ახლა, რომ თქვენ გაქვთ ნათელი იდეა ხილვადობის სფეროებში, ჩვენ დავამატებთ დახურვის მათ. სქემები არიან გამონათქვამები, როგორც წესი, ფუნქციები, რომლებიც მუშაობენ გარკვეულ კონტექსტში ცვლადების კომპლექტით. ან, მარტივი სიტყვები, შიდა ფუნქციები, რომლებიც ეხება გარე ფუნქციების ადგილობრივ ცვლადებს ფორმის დახურვას. Მაგალითად:

ფუნქციის დამატება (x) (დაბრუნება x + y;);) var add5 \u003d დამატება (5); var no8 \u003d add5 (3); Alert (no8); / / ბრუნდება 8.

Blimey! Რა ხდება აქ? გავიგოთ:

1. როდესაც ჩვენ მოვუწოდებთ add ფუნქციას, ის დააბრუნებს ფუნქციას.

2. ეს ფუნქცია ახსენებს კონტექსტს და იმახსოვრებს იმას, თუ როგორ არის პარამეტრი x ამ დროს (I.E., ამ შემთხვევაში, ღირებულება 5)

3. როდესაც Add ფუნქციის შედეგია Add5 ცვლადი, ის ყოველთვის იცის, რა არის x- ის შექმნისას.

4. ცვლადი Add5 ეხება ფუნქციას, რომელიც ყოველთვის დაამატებთ ღირებულებას 5 მასზე გადაცემულ ნებისმიერ არგუმზე.

5. ეს იმას ნიშნავს, რომ როდესაც ჩვენ ვუწოდებთ ADD5 ღირებულებას 3-ით, ის 5-დან 3-მდე ჩამოყალიბდება და 8-ს დაუბრუნდება.

სინამდვილეში, JavaScript მსოფლიოში, Add5 ფუნქცია ასე გამოიყურება:

ფუნქცია add5 (y) (დაბრუნება 5 + y;)

ციკლის ცნობილი პრობლემა
რამდენჯერ შეიქმნა ციკლები, რომელშიც უნდოდა, რომ არავითარი ღირებულების მინიჭება, მაგალითად, ელემენტს და მიხვდა, რომ მხოლოდ უკანასკნელი ღირებულება დავბრუნდი?

მცდარიაპელირება

მოდით შევხედოთ ამ არასწორი კოდი, რომელიც ქმნის 5 ელემენტს , დასძენს ღირებულება მე, როგორც ტექსტი თითოეული ელემენტი და onclick, რომელიც სავარაუდოდ აწარმოოს მზადყოფნაში ღირებულება i მინიშნება, I.E. იგივე მნიშვნელობა, როგორც ელემენტის ტექსტში. მაშინ ელემენტები დაემატება დოკუმენტს:

<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function () { alert(i); }; document.body.appendChild(link); } } window.onload = addLinks;

თითოეული ელემენტი შეიცავს ზუსტ ტექსტს, ანუ. "ლინკი 0", "ლინკი 1" და ა.შ. მაგრამ რაც არ უნდა იყოს ბმული, დაწკაპავთ, ის გვიჩვენებს გაფრთხილებას ნომერზე 5. რა არის საქმე? მიზეზი ისაა, რომ ცვლადის ღირებულება 1-ით იზრდება თითოეული ციკლის თითოეული iteration, და რადგან OnClick ღონისძიება არ არის შესრულებული, მაგრამ უბრალოდ ვრცელდება ელემენტს ღირებულება იზრდება.

აქედან გამომდინარე, ციკლი განაგრძობს მუშაობას, სანამ მე ვიქნები ტოლი 5, რომელიც ბოლო ღირებულებაა AddLinks- ის ფუნქციამდე. გარდა ამისა, ყოველ ჯერზე onclick ღონისძიება გამოიწვია, ბოლო ღირებულება მე აღებული.

სათანადო მიმართვა

რა უნდა გააკეთოთ, შექმნას დახურვა. შედეგად, როდესაც თქვენ ვრცელდება ღირებულება i onclick ღონისძიება ღონისძიება , მე ვიქნები იმ დროისათვის. მაგალითად, ასე რომ:

ფუნქცია addlinks () (for (var i \u003d 0, ლინკი, მე<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function (num) { return function () { alert(num); }; }(i); document.body.appendChild(link); } } window.onload = addLinks;

ამ კოდის გამოყენებით, თუ პირველ ელემენტზე დაწკაპავთ, გაფრთხილება "0", მეორე - "1" და ა.შ. გამოსავალი ის არის, რომ შიდა ფუნქცია გამოიყენება onclick ღონისძიება ქმნის დახურვას, რომელშიც რიცხვი პარამეტრი სააპელაციო, I.E. იმ დროს მე.

ეს ფუნქცია "იხსენებს" სასურველ ღირებულებას და შემდეგ შეიძლება დაბრუნდეს შესაბამისი ციფრი, როდესაც OnClick მოვლენა გამოიწვია.

უსაფრთხო-შესრულების ფუნქციები

უსაფრთხო შესრულების ფუნქციები ისეთი ფუნქციებია, რომლებიც დაუყოვნებლივ დაიწყებენ და ქმნიან მათ დახურვას. განვიხილოთ მაგალითი:

(ფუნქცია () (var dog \u003d "გერმანული მწყემსი"; alert (dog);) (); გაფრთხილება (ძაღლი); / / ბრუნდება განუსაზღვრელი.

ასე რომ, ძაღლი ცვლადი ხელმისაწვდომია მხოლოდ ამ კონტექსტში. წარმოიდგინეთ, ფარული ცვლადი ძაღლი ... მაგრამ, ჩემი მეგობრები, ყველაზე საინტერესო რამ იწყება ამით! ეს მოგვარდა ჩვენს პრობლემას ციკლით და ასევე არის Yahoo JavaScript მოდულის ნიმუშის საფუძველი.

Yahoo JavaScript მოდული ნიმუში

ამ ნიმუშის არსი ის არის, რომ იგი იყენებს უსაფრთხო-შესრულებადი ფუნქციას, რათა შეიქმნას დახურვა, ამიტომ საშუალებას იძლევა გამოიყენოს კერძო და საჯარო თვისებები და მეთოდები. მარტივი მაგალითი:

var person \u003d ფუნქცია () (// პირადი var სახელი \u003d "რობერტ"; დაბრუნება (GettName: ფუნქცია () (დაბრუნების სახელი), SETNAME: ფუნქცია (NEWNAME) (სახელი \u003d NEWNAME;)); alert (person.name); // undefined alert (person.getname ()); / / "რობერტ" პიროვნება ("რობერტ ნიმარი"); alert (person.getname ()); // "რობერტ ნიმენი"

უპირატესობა ამ მიდგომის არის ის, რომ თქვენ შეგიძლიათ განსაზღვროთ საკუთარ თავს, რომელიც ღია იქნება თქვენს ობიექტში (და შეიძლება შეიცვალოს), და ეს დახურულია, რომელსაც არავის შეუძლია დაუკავშირდეს ან შეცვალოს. სახელი ცვლადი იმალება ფუნქციის კონტექსტში, მაგრამ ხელმისაწვდომი იქნება GetName და SetName ფუნქციები, რადგან ისინი ქმნიან დახურვას, სადაც არის სახელი ცვლადი.

დასკვნა

მე გულწრფელად ვიმედოვნებ, რომ ამ სტატიის წაკითხვის შემდეგ ახალბედა და გამოცდილი პროგრამისტები მიიღეს უფრო მკაფიო იდეა, თუ როგორ ხილვადობის სამუშაო ადგილებზე ხილვადობა და დახურვა. კითხვები და მიმოხილვები არის მისასალმებელი, და თუ თქვენ გაქვთ რაიმე მნიშვნელოვანი, რათა რაღაც, მაშინ შემიძლია განაახლოთ სტატია.

კარგი კოდირება!

სქემები JavaScript- ში. გამოიყენება ცვლადი ღირებულებების დამალვა და მაღაზიის ფუნქციები. საქმე იმაშია, რომ დახურვისას, ერთი ფუნქცია იქმნება, რომელშიც ცვლადები არის მითითებული და რაც მისი ოპერაციის შედეგად დაბრუნდა მისი წყობილი ფუნქცია. შემდეგ, მასში (ძირითად ფუნქციაში), ჩადგმული ფუნქცია იქმნება, რომელშიც გარკვეული ოპერაციები მზადდება ცვლადი ფუნქციის ცვლადებით და რომელიც ამ ოპერაციების შედეგს აბრუნებს. შემდეგი, მთავარი ფუნქცია თანაბარია ცვლადი - ეს ცვლადი შეიძლება მოიხსენიოთ რამდენი დრო და თუმცა, ძირითადი ფუნქციის ცვლადების ღირებულებები ინახება და განახლდება. ის "დახურულია".

როგორც მოგეხსენებათ, JavaScript- ში ადგილობრივი ცვლადების ხილვადობის სფეროში (გამოაცხადა var სიტყვა) ეს არის ფუნქციის ორგანო, რომლის ფარგლებშიც ისინი განისაზღვრება.

თუ სხვა ფუნქციის ფუნქციას გამოაცხადებთ, პირველი იღებს ამ უკანასკნელის ცვლადებსა და არგუმენტებს:

კოდი: ფუნქცია Outerfn (Myarg) (
Var myvar;
ფუნქცია Innerfn ()
/ / Myvar და Myarg- ს წვდომა
}
}

ამავდროულად, ასეთი ცვლადები კვლავაც არსებობს და ხელმისაწვდომი შიდა ფუნქციის შემდეგ, გარე ფუნქციის შემდეგაც კი, როდესაც ისინი განისაზღვრება.

განვიხილოთ მაგალითი - ფუნქცია, რომელიც დააბრუნებს Eigenvalues- ს რაოდენობას:

კოდი: ფუნქციის შემოქმედება ()
var numberofcalls \u003d 0;
დაბრუნების ფუნქცია ()
დაბრუნება ++ Numberofcalls;
}
}
var fn \u003d createcounter ();
fn (); // ერთი
fn (); // 2.
fn (); // 3.

ამ მაგალითში, ფუნქცია შემოქმედებითმა ფუნქციამ გამოიყენოს NURNOFOFCALLS ცვლადი, რომელიც დაზოგავს მის ზარებს შორის სასურველ მნიშვნელობას (ნაცვლად იმისა, რომ არსებობდეს შემოქმედებითი დაბრუნებით).

ეს თვისებებია, რომ JavaScript- ში ასეთი "წყობილი" ფუნქციები ეწოდება დახურვას (ტერმინი, რომელიც მოვიდა პროგრამირების ფუნქციურ ენებზე) - ისინი "უფრო ახლოს არიან", რომლებიც განისაზღვრება ფუნქციის ცვლადები და არგუმენტები.

დახურვის გამოყენება

ამარტივებს პატარა მაგალითს ზემოთ - ამოღება საჭიროება ცალკე მოვუწოდებთ Createcounter ფუნქცია, რაც მას ანექსიური და მოუწოდებს მას დაუყოვნებლივ მას შემდეგ:

კოდი: var fn \u003d (ფუნქცია ()
var numberofcalls \u003d 0;
დაბრუნების ფუნქცია ()
დაბრუნება ++ Numberofcalls;
}
})();

ასეთმა დიზაინმა მოგვცა მონაცემების დაკმაყოფილება ფუნქციისთვის, რომელიც თავის გამოწვევებს შორის დარჩა, არის დახურვის ერთ-ერთი გამოყენება. სხვა სიტყვებით რომ ვთქვათ, მათ დახმარებით შეგვიძლია შევქმნათ ფუნქციები, რომლებსაც აქვთ ცვლადი სახელმწიფო.

დახურვის სხვა კარგი გამოყენება - ფუნქციების შექმნა, თავის მხრივ, ასევე ქმნის ფუნქციებს - რა იქნება ზოგიერთს T.N. MetaProgramming.
Მაგალითად:

კოდი: Var CreateHelloFunction \u003d ფუნქცია (სახელი) (
დაბრუნების ფუნქცია ()
Alert ("გამარჯობა," + სახელი);
}
}
var sayhellohabrahabr \u003d creathellofunction ("Habrahabr");
sayhellohabrahabr (); // შეტყობინებები "გამარჯობა, ჰაბრაჰაბარი"

დახურვის წყალობით, დაბრუნებული ფუნქცია "ახსოვს" პარამეტრების გადაცემის ფუნქციებს, რომლებიც ამგვარი რამ გვჭირდება.

მსგავსი სიტუაცია ხდება მაშინ, როდესაც ჩვენ არ დავბრუნდებით შიდა ფუნქციას, და ყოველ შემთხვევაში გათიშეთ - მას შემდეგ, რაც ღონისძიება ჩნდება ფუნქციის შესრულების შემდეგ, დახურვა კვლავ არ დაკარგავს მონაცემებს, როდესაც მონაცემთა გამამხნევებელი მონაცემები იქმნება.

განვიხილოთ ოდნავ უფრო რთული მაგალითი - მეთოდი, რომელიც ფუნქციონირებს ფუნქციონირებს კონკრეტულ კონტექსტში (I.E., ობიექტი, რომელსაც ეს სიტყვა მიუთითებს მასში).

კოდი: ფუნქცია. Prototype.bind \u003d ფუნქცია (კონტექსტი) (
var fn \u003d ეს;
დაბრუნების ფუნქცია ()
დაბრუნება FN.Apply (კონტექსტი, არგუმენტები);
};
}
var hellopage \u003d (
სახელი: "Habrahabr",
init: ფუნქცია ()
Alert ("გამარჯობა," + this.name);
}
}
//Window.onload \u003d hellopage.init; // Alertnul იქნებოდა undefined, რადგან ეს ფანჯარაში მიუთითებს
window.onload \u003d hellopage.init.bind (hellopage); / / ახლა ყველაფერი მუშაობს

ამ მაგალითში, დახურვის დახმარებით, ფუნქცია, გამოიწვია სავალდებულო "ომმა, ახსოვს თავდაპირველ ფუნქციასა და მისთვის კონტექსტში.

შემდეგი, ფუნდამენტურად განსხვავებული გამოყენება დახურვის - მონაცემთა დაცვის (encapsulation). განვიხილოთ შემდეგი დიზაინი:

კოდი: (ფუნქცია () (

})();

ცხადია, დახურვის შიგნით ჩვენ გვაქვს ყველა გარე მონაცემების ხელმისაწვდომობა, მაგრამ მას აქვს საკუთარი. ამის გამო, ჩვენ შეგვიძლია შემოგთავაზოთ კოდექსის ნაწილი, როგორიცაა დიზაინი, რათა ადგილობრივ ცვლადების დახურვის მიზნით. (მისი გამოყენების ერთი მაგალითი ჩანს jQuery ბიბლიოთეკის კოდექსში, რომელიც გარს ყველა კოდის დახურვას, ისე, რომ არ გამოვიყენოთ ცვლადები მხოლოდ მასზე).

თუმცა, არსებობს, ერთი ასოცირებული ასეთი გამოყენების ხაფანგში - მნიშვნელობა სიტყვა ეს დაკარგა შიგნით დახურვის. იგი მოგვარდება შემდეგნაირად:

კოდი: (ფუნქცია () (
/ / ყველაზე მაღალი ეს გაგრძელდება
)). ზარი (ეს);

განვიხილოთ სხვა მიღება იმავე სერიიდან. იგი ფართოდ გავრცელდა Yahoo UI- ის დეველოპერების მიერ, მას "მოდულის ნიმუში" უწოდებს და მთელ სტატიას ოფიციალურ ბლოგზე წერა.
მოდით გვქონდეს ობიექტი (singleton), რომელიც შეიცავს ნებისმიერ მეთოდებსა და თვისებებს:

კოდი: var mymodule \u003d (
სახელი: "Habrahabr",
SayPreved: ფუნქცია (სახელი) (
Alert ("preved" + name.touppercase ())
},
ეს. esaypreved (this.name);
}
}
Mymodule.sayprevedtohabrahabr ();

დახურვის დახმარებით, ჩვენ შეგვიძლია გავაკეთოთ მეთოდები და თვისებები, რომლებიც არ გამოიყენება ობიექტის გარეთ, კერძო (I.. ხელმისაწვდომია მხოლოდ მისთვის):

კოდი: var mymodule \u003d (ფუნქცია () ()
Var name \u003d "habrahabr";
ფუნქცია SayPreved ()
Alert ("preved" + name.touppercase ());
}
Დაბრუნების (
SayPrevedtohabraHabr: ფუნქცია ()
SayPreved (სახელი);
}
}
})();
Mymodule.sayprevedtohabrahabr (); / / Alerts "Preved Habrahabr"

საბოლოოდ, მინდა აღწერო საერთო შეცდომა, რომ ბევრი ჩავა შევიდა stupor იმ შემთხვევაში, თუ როგორ დახურვის მუშაობა.

მოდით გვქონდეს მასივი ბმულები და ჩვენი ამოცანაა, რომ ისე, რომ როდესაც თქვენ დააჭირეთ თითოეულ allert, მისი თანმიმდევრობის ნომერი არის ნაჩვენები.
პირველი გადაწყვეტილება, რომელიც გონება ჰგავს:

კოდი: ამისთვის (var i \u003d 0; მე< links.length; i++) {
Alert (i);
}
}

სინამდვილეში, აღმოჩნდება, რომ როდესაც თქვენ დააჭირეთ ნებისმიერ ბმულს, იგივე ნომერი არის ნაჩვენები - ღირებულება ბმულები. სიგრძე. Რატომ ხდება ეს? დახურვისთან დაკავშირებით, გამოცხადებული დამხმარე ცვლადი მე განაგრძობს არსებობას, ხოლო იმ მომენტში, როდესაც ჩვენ დააჭირეთ ბმულს. მას შემდეგ, რაც იმ დროს ციკლი უკვე გავიდა, მე რჩება კავშირების რაოდენობის ტოლი - ეს მნიშვნელობა ჩვენ ხილულია.

ეს პრობლემა მოგვარდება შემდეგნაირად:

კოდი: ამისთვის (var i \u003d 0; მე< links.length; i++) {
(ფუნქცია (i)
ბმულები [I] .ONClick \u003d ფუნქცია ()
Alert (i);
}
)) (მე);
}

აქ, კიდევ ერთი დახურვის დახმარებით, ჩვენ "ჩრდილი" ცვლადი მე, მას ქმნის მას ასლი თავის ადგილობრივ ზონაში ხილვადობის ყოველ ციკლში. მადლობა ამ, ყველაფერი მუშაობს ახლა, როგორც ჩაფიქრებული.

Სულ ეს არის. ეს სტატია, რა თქმა უნდა, არ აცხადებს, რომ ამომწურავი, მაგრამ ვინმე, იმედი მაქვს, კვლავ ეხმარება გაერკვნენ.

zy.
ზარების დაზოგვისთვის ადვილად გამოიყენოთ func_name.attr ტიპი:

კოდი: ფუნქციის რაოდენობა (გადატვირთვა) (
თუ (გადატვირთვა || countit.cnt) countit.cnt \u003d 0;
დაბრუნება COMENT.CNT ++;