ලූප තුළ ජාවාස්ක්‍රිප්ට් වසා දැමීම - සරල ප්‍රායෝගික උදාහරණය


2826

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

එය මෙය ප්‍රතිදානය කරයි:

මගේ වටිනාකම: 3
මගේ වටිනාකම: 3
මගේ වටිනාකම: 3

එය ප්‍රතිදානය කිරීමට මා කැමති නමුත්:

මගේ වටිනාකම: 0
මගේ වටිනාකම: 1
මගේ වටිනාකම: 2


සිදුවීම් ශ්‍රාවකයින් භාවිතා කිරීමෙන් ශ්‍රිතය ක්‍රියාත්මක කිරීම ප්‍රමාද වන විට එකම ගැටළුව ඇතිවේ:

var buttons = document.getElementsByTagName("button");
// let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
  // as event listeners
  buttons[i].addEventListener("click", function() {
    // each should log its value.
    console.log("My value: " + i);
  });
}
<button>0</button>
<br />
<button>1</button>
<br />
<button>2</button>

… හෝ අසමමුහුර්ත කේතය, උදා: පොරොන්දු භාවිතා කිරීම:

// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));

for (var i = 0; i < 3; i++) {
  // Log `i` as soon as each promise resolves.
  wait(i * 100).then(() => console.log(i));
}

සංස්කරණය කරන්න: එය ද පැහැදිලි වේ for inහා for ofවළළු:

const arr = [1,2,3];
const fns = [];

for(i in arr){
  fns.push(() => console.log(`index: ${i}`));
}

for(v of arr){
  fns.push(() => console.log(`value: ${v}`));
}

for(f of fns){
  f();
}

මෙම මූලික ගැටලුවට විසඳුම කුමක්ද?


55
ඔබ funcsසංඛ්‍යාත්මක දර්ශක භාවිතා කරන්නේ නම්, ඔබට අරාව වීමට අවශ්‍ය නැති බව ඔබට විශ්වාසද ? හිස ඔසවන්න.
ඩෑන්මන්

23
මෙය සැබවින්ම අවුල් සහගත ගැටලුවකි. එය තේරුම් ගැනීමට මෙම ලිපිය මට උපකාර කරයි . එය අන් අයටද උපකාර කළ හැකිය.
පරිශීලක 3199690

4
තවත් සරල හා පැහැදිලි කළ විසඳුමක්: 1) කැදැලි කාර්යයන් ඒවාට “ඉහළින්” ඇති විෂය පථයට ප්‍රවේශය ඇත ; 2) එය වසා දැමීමට විසඳුමක් ... "ඒ වසා මව් කාර්යය වසා පසුව පවා, මව් විෂය පථය ලබාගැනීම ශ්රිතයක් වේ".
පීටර් ක්‍රවුස්

2
වඩා හොඳ අවබෝධ කර නොගත් javascript.info/tutorial/advanced-functions
සෞරබ් අහුජා

36
දී ES6 , සුළු පටු විසඳුමක් විචල්ය ප්රකාශ කිරීම යි මම සමග කිරීමටද කම්බියක් ශරීරයට scoped වන.
ටොමාස් නිකොඩිම්

Answers:


2155

හොඳයි, ගැටළුව වන්නේ iඔබේ එක් එක් නිර්නාමික ශ්‍රිතය තුළ විචල්‍යය ශ්‍රිතයට පිටතින් එකම විචල්‍යයට බැඳී තිබීමයි.

සම්භාව්ය විසඳුම: වසා දැමීම්

ඔබට කිරීමට අවශ්‍ය වන්නේ එක් එක් ශ්‍රිතය තුළ ඇති විචල්‍යය ශ්‍රිතයෙන් පිටත වෙනම, වෙනස් නොවන අගයකට බැඳීමයි:

var funcs = [];

function createfunc(i) {
  return function() {
    console.log("My value: " + i);
  };
}

for (var i = 0; i < 3; i++) {
  funcs[i] = createfunc(i);
}

for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

ජාවාස්ක්‍රිප්ට් හි බ්ලොක් විෂය පථයක් නොමැති බැවින් - ශ්‍රිත විෂය පථය පමණක් - ශ්‍රිත නිර්මාණය නව ශ්‍රිතයක් තුළට ඔතා ගැනීමෙන්, ඔබ අදහස් කළ පරිදි “i” හි අගය ඉතිරිව ඇති බව සහතික කරයි.


ES5.1 විසඳුම: forEach

Array.prototype.forEach(2015 දී) සාපේක්ෂව පුළුල් ලෙස ලබා ගත හැකි වීමත් සමඟ, මූලික වශයෙන් සාරධර්ම රාශියක් ඉක්මවා නැවත ක්‍රියා කිරීම සම්බන්ධ අවස්ථාවන්හිදී .forEach(), සෑම ක්‍රියාවලියක් සඳහාම පැහැදිලි වසා දැමීමක් ලබා ගැනීම සඳහා පිරිසිදු ස්වාභාවික ක්‍රමයක් සපයන බව සඳහන් කිරීම වටී . එනම්, ඔබට යම් ආකාරයක අගයන් (DOM යොමු කිරීම්, වස්තූන්, ඕනෑම දෙයක්) ඇති බව උපකල්පනය කර, එක් එක් මූලද්‍රව්‍යයට විශේෂිත වූ ඇමතුම් ලබා ගැනීමේ ගැටළුව පැන නගී, ඔබට මෙය කළ හැකිය:

var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
  // ... code code code for this one element
  someAsynchronousFunction(arrayElement, function() {
    arrayElement.doSomething();
  });
});

අදහස නම්, .forEachලූපය සමඟ භාවිතා කරන ඇමතුම් ආපසු ගැනීමේ ශ්‍රිතයේ සෑම ආයාචනයක්ම එය වසා දැමීමයි. එම හසුරුවන්නාට ලබා දුන් පරාමිතිය, පුනරාවර්තනයේ නිශ්චිත පියවරට විශේෂිත වූ අරාව මූලද්‍රව්‍යයයි. එය අසමමුහුර්ත ඇමතුමක භාවිතා කරන්නේ නම්, එය පුනරාවර්තනයේ වෙනත් පියවරයන්හි පිහිටුවා ඇති වෙනත් කිසිදු ඇමතුම් සමඟ ගැටෙන්නේ නැත.

ඔබ jQuery හි වැඩ කරන්නේ නම්, $.each()ශ්‍රිතය ඔබට සමාන හැකියාවක් ලබා දෙයි.


ES6 විසඳුම: let

ECMAScript 6 (ES6) නව letසහ constමූල පද හඳුන්වා දෙයි var. නිදසුනක් ලෙස, letපාදක දර්ශකයක් සහිත ලූපයක, ලූපය හරහා එක් එක් නැවතීමේ ක්‍රියාවලියට iලූප් විෂය පථය සමඟ නව විචල්‍යයක් ඇත, එබැවින් ඔබේ කේතය ඔබ බලාපොරොත්තු වන පරිදි ක්‍රියා කරයි. බොහෝ සම්පත් තිබේ, නමුත් 2 තොරතුරු වල බ්ලොක්-ස්කොපිං පෝස්ට් විශාල තොරතුරු ප්‍රභවයක් ලෙස මම නිර්දේශ කරමි .

for (let i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("My value: " + i);
  };
}

කෙසේ වෙතත්, එඩ්ජ් 14 ට පෙර IE9-IE11 සහ එජ් සහාය දක්වන letනමුත් ඉහත වැරැද්ද ලබා ගන්න (ඒවා iසෑම විටම නව එකක් නිර්මාණය නොකරයි , එබැවින් ඉහත සඳහන් සියලු කාර්යයන් අප භාවිතා කළ ආකාරයටම 3 ට ලොග් වනු ඇත var). 14 වන දාරය අවසානයේ එය නිවැරදිව තේරුම් ගනී.


7
function createfunc(i) { return function() { console.log("My value: " + i); }; }එය විචල්‍යය භාවිතා කරන නිසා තවමත් වසා නැත i?
レ ッ ク ク

55
අවාසනාවකට මෙන්, මෙම පිළිතුර යල් පැන ගිය එකක් වන අතර නිවැරදි පිළිතුර පතුලේ කිසිවෙකු නොදකිනු ඇත - භාවිතා Function.bind()කිරීම නියත වශයෙන්ම මේ වන විට වඩාත් යෝග්‍ය වේ, stackoverflow.com/a/19323214/785541 බලන්න .
ව්ලැඩිමීර් පැලන්ට්

81
@Wladimir: බව ඔබේ යෝජනාව .bind()වන්නේ "නිවැරදි පිළිතුර" හරි නෑ. ඔවුන් සෑම කෙනෙකුටම තමන්ගේම ස්ථානයක් ඇත. සමග .bind()ඔබ බන්ධන තොරව තර්ක බැඳ නොහැකි thisවටිනාකම. iසමහර විට අවශ්‍ය වන ඇමතුම් අතර විකෘති කිරීමේ හැකියාවක් නොමැතිව තර්කයේ පිටපතක් ඔබට ලැබේ. එබැවින් ඒවා බෙහෙවින් වෙනස් ඉදිකිරීම් වේ, .bind()ක්‍රියාත්මක කිරීම ically තිහාසික වශයෙන් මන්දගාමී වී ඇති බව සඳහන් නොකල යුතුය. සරල උදාහරණයෙන් නිසැකවම ක්‍රියාත්මක වනු ඇත, නමුත් වසා දැමීම තේරුම් ගැනීමට වැදගත් සංකල්පයක් වන අතර ප්‍රශ්නය එයයි.
කුකී රාක්ෂයා

8
කරුණාකර මෙම ආපසු යැවීමේ ශ්‍රිත හක්ක භාවිතා කිරීම නවත්වන්න, ඒ වෙනුවට [] .forEach හෝ [] .map භාවිතා කරන්න, මන්ද ඔවුන් එකම විෂය පථ විචල්‍යයන් නැවත භාවිතා කිරීමෙන් වළකින්න.
ක්‍රිස්ටියන් ලෑන්ඩ්ග්‍රන්

32
H ක්‍රිස්ටියන් ලෑන්ඩ්ග්‍රන්: එය ප්‍රයෝජනවත් වන්නේ ඔබ අරාව නැවත ක්‍රියාත්මක කරන්නේ නම් පමණි. මෙම ශිල්පීය ක්‍රම "හක්ක" නොවේ. ඒවා අත්‍යවශ්‍ය දැනුමකි.

381

උත්සාහ කරන්න:

var funcs = [];
    
for (var i = 0; i < 3; i++) {
    funcs[i] = (function(index) {
        return function() {
            console.log("My value: " + index);
        };
    }(i));
}

for (var j = 0; j < 3; j++) {
    funcs[j]();
}

සංස්කරණය කරන්න (2014):

පුද්ගලිකව මම හිතන්නේ @ ඔස්ට් භාවිතා.bind කිරීම පිළිබඳ වඩාත් මෑත පිළිතුර මේ ආකාරයේ දෙයක් කිරීමට දැන් හොඳම ක්‍රමයයි. ලෝ-ඩෑෂ් / underscore ගේ ද තිබෙන _.partialඔබ සමඟ අවුල් කිරීමට අවශ්ය නොවන හෝ අවශ්ය වන විට bindගේ thisArg.


2
ගැන පැහැදිලි කිරීමක් }(i));තිබේද?
aswzen

3
waswzen මම හිතන්නේ එය ශ්‍රිතයට iතර්කය ලෙස සම්මත indexවේ.
ජෙට් බ්ලූ

එය ඇත්ත වශයෙන්ම දේශීය විචල්‍ය දර්ශකය නිර්මාණය කරයි.
අභිෂේක් සිං

1
වහාම ක්‍රියාකාරී ප්‍රකාශනය ආරාධනා කරන්න, හෝ IIFE. (i) යනු නිර්නාමික ශ්‍රිත ප්‍රකාශනය සඳහා වන තර්කය වන අතර එය වහාම ක්‍රියාත්මක වන අතර i වෙතින් දර්ශකය සකසා ඇත.
බිත්තර

350

තවම සඳහන් කර නොමැති තවත් ක්‍රමයක් නම් භාවිතය Function.prototype.bind

var funcs = {};
for (var i = 0; i < 3; i++) {
  funcs[i] = function(x) {
    console.log('My value: ' + x);
  }.bind(this, i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}

යාවත්කාලීන කරන්න

@Squint සහ kmekdev විසින් පෙන්වා දී ඇති පරිදි, ඔබට පළමුව ලූපයෙන් පිටත ශ්‍රිතය නිර්මාණය කිරීමෙන් සහ ප්‍රති results ල ලූපය තුළ බැඳීමෙන් ඔබට වඩා හොඳ කාර්ය සාධනයක් ලැබේ.

function log(x) {
  console.log('My value: ' + x);
}

var funcs = [];

for (var i = 0; i < 3; i++) {
  funcs[i] = log.bind(this, i);
}

for (var j = 0; j < 3; j++) {
  funcs[j]();
}


මේ දිනවල මම කරන්නේත් මෙයයි, මමත් ලො-ඩෑෂ් / යටි ඉරි _.partial
ඇඳීමට

17
.bind()ECMAScript 6 විශේෂාංග සමඟ බොහෝ දුරට යල්පැන යනු ඇත. ඇරත්, මෙය සැබවින්ම පුනරාවර්තනයකට ශ්‍රිත දෙකක් නිර්මාණය කරයි. පළමුව නිර්නාමික, පසුව ජනනය කළ එක .bind(). වඩා හොඳ භාවිතය වනුයේ එය ලූපයෙන් පිටත නිර්මාණය කිරීමයි, පසුව .bind()එය ඇතුළත ය.

5
qusquint @mekdev - ඔබ දෙදෙනාම නිවැරදිය. bindභාවිතා කරන ආකාරය නිරූපණය කිරීම සඳහා මගේ ආරම්භක උදාහරණය ඉක්මනින් ලියා ඇත. ඔබගේ යෝජනා අනුව මම තවත් උදාහරණයක් එකතු කර ඇත්තෙමි.
ඔස්ට්

5
මම හිතන්නේ O (n) ලූප දෙකකට වඩා ගණනය කිරීම නාස්ති කරනවා වෙනුවට (var i = 0; i <3; i ++) {log.call (මෙය, i); }
user2290820

1
.bind () විසින් පිළිගත් පිළිතුර මඟින් ප්ලස් ෆිදල්ස් සමඟ යෝජනා කරයි this.
niry

272

ක්ෂණිකව ආයාචිත ශ්‍රිත ප්‍රකාශනයක් භාවිතා කිරීම , දර්ශක විචල්‍යයක් කොටු කර ගැනීම සඳහා සරලම හා වඩාත්ම කියවිය හැකි ක්‍රමය:

for (var i = 0; i < 3; i++) {

    (function(index) {

        console.log('iterator: ' + index);
        //now you can also loop an ajax call here 
        //without losing track of the iterator value:   $.ajax({});
    
    })(i);

}

මෙය iඅප විසින් නිර්වචනය කරන නිර්නාමික ශ්‍රිතයට අනුකාරකය යවයි index. මෙය වසා දැමීමක් නිර්මාණය කරයි, එහිදී iIIFE තුළ ඇති ඕනෑම අසමමුහුර්ත ක්‍රියාකාරිත්වයක විචල්‍යය පසුකාලීන භාවිතය සඳහා සුරකිනු ඇත.


10
වැඩිදුර කේත කියවීමේ හැකියාව සහ iකුමක් දැයි ව්‍යාකූල වීම වළක්වා ගැනීම සඳහා , මම ක්‍රියාකාරී පරාමිතිය ලෙස නම් කරමි index.
කයිල් ෆැල්කනර්

5
මුල් ප්‍රශ්නයේ විස්තර කර ඇති අරාව ෆන්ක්ස් අර්ථ දැක්වීමට ඔබ මෙම තාක්ෂණය භාවිතා කරන්නේ කෙසේද ?
නිකෝ

IcNico මුල් ප්‍රශ්නයෙහි පෙන්වා ඇති ආකාරයටම, ඔබ ඒ indexවෙනුවට භාවිතා කරනු ඇත i.
ජේ.එල්.රිෂේ

@ ජේ.එල්.රිෂේvar funcs = {}; for (var i = 0; i < 3; i++) { funcs[i] = (function(index) { return function() {console.log('iterator: ' + index);}; })(i); }; for (var j = 0; j < 3; j++) { funcs[j](); }
නිකෝ

1
ICNico OP හි විශේෂිත අවස්ථාවෙහිදී, ඒවා සංඛ්‍යා ඉක්මවා යමින් පවතී, එබැවින් මෙය එතරම් වැදගත් කාරණයක් නොවනු ඇත .forEach(), නමුත් බොහෝ විට, අරාවකින් ආරම්භ forEach()වන විට හොඳ තේරීමක් වේ, වැනි:var nums [4, 6, 7]; var funcs = {}; nums.forEach(function (num, i) { funcs[i] = function () { console.log(num); }; });
JLRishe

168

සාදයට ටිකක් පරක්කුයි, නමුත් මම අද මෙම ප්‍රශ්නය ගවේෂණය කරමින් සිටි අතර බොහෝ පිළිතුරු ජාවාස්ක්‍රිප්ට් විෂය පථයන්ට සලකන ආකාරය සම්පූර්ණයෙන් ආමන්ත්‍රණය නොකරන බව දුටුවෙමි.

වෙනත් බොහෝ අය සඳහන් කළ පරිදි ගැටළුව වන්නේ අභ්‍යන්තර ශ්‍රිතය එකම iවිචල්‍යය යොමු කිරීමයි . ඉතින් ඇයි අපි එක් එක් පුනරාවර්තනය සඳහා නව දේශීය විචල්‍යයක් නිර්මාණය නොකරන්නේ, ඒ වෙනුවට අභ්‍යන්තර ශ්‍රිත යොමුව තිබේද?

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    var ilocal = i; //create a new local variable
    funcs[i] = function() {
        console.log("My value: " + ilocal); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

පෙර මෙන්, සෑම අභ්‍යන්තර ශ්‍රිතයක්ම පවරා ඇති අවසාන අගය ප්‍රතිදානය කළ තැන i, දැන් සෑම අභ්‍යන්තර ශ්‍රිතයක්ම පවරා ඇති අවසාන අගය ප්‍රතිදානය කරයි ilocal. නමුත් සෑම පුනරාවර්තනයකටම එය තිබිය යුතු නොවේද ilocal?

හැරෙනවා, ඒක තමයි ප්‍රශ්නය. සෑම පුනරාවර්තනයක්ම එකම විෂය පථයක් බෙදා ගනී, එබැවින් පළමු නැවත සිදුකිරීමේ සෑම ක්‍රියාවක්ම නැවත ලියයි ilocal. MDN වෙතින් :

වැදගත්: ජාවාස්ක්‍රිප්ට් වලට බ්ලොක් විෂය පථයක් නොමැත. බ්ලොක් එකක් සමඟ හඳුන්වා දී ඇති විචල්‍යයන් අඩංගු ශ්‍රිතයට හෝ ස්ක්‍රිප්ටයට පරික්ෂා කර ඇති අතර ඒවා සැකසීමේ ප්‍රති block ල වාරණයෙන් ඔබ්බට පවතී. වෙනත් වචන වලින් කිවහොත්, වාරණ ප්‍රකාශයන් විෂය පථයක් හඳුන්වා නොදේ. “හුදකලා” කුට්ටි වලංගු වාක්‍ය ඛණ්ඩයක් වුවද, ඔබට ජාවාස්ක්‍රිප්ට් හි හුදකලා කොටස් භාවිතා කිරීමට අවශ්‍ය නැත, මන්ද ඔවුන් ඔබ සිතන දේ නොකරන නිසා, ඔවුන් සී හෝ ජාවාහි එවැනි කොටස් වැනි දෙයක් කරයි යැයි ඔබ සිතන්නේ නම්.

අවධාරණය සඳහා නැවත අවධාරණය කර ඇත:

JavaScript හි වාරණ විෂය පථයක් නොමැත. බ්ලොක් එකක් සමඟ හඳුන්වා දුන් විචල්‍යයන් අඩංගු ශ්‍රිතයට හෝ ස්ක්‍රිප්ටයට පරික්ෂා කෙරේ

ilocalඑක් එක් පුනරාවර්තනයේ දී එය ප්‍රකාශ කිරීමට පෙර පරීක්ෂා කිරීමෙන් අපට මෙය දැකිය හැකිය :

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
  console.log(ilocal);
  var ilocal = i;
}

මෙම දෝෂය මෙතරම් ව්‍යාකූල වීමට හේතුව මෙයයි. ඔබ විචල්‍යයක් නැවත ප්‍රකාශයට පත් කළද, ජාවාස්ක්‍රිප්ට් දෝෂයක් නොදක්වන අතර ජේඑස්ලින්ට් අනතුරු ඇඟවීමක්වත් නොකරයි. මෙය විසඳීමට ඇති හොඳම ක්‍රමය වන්නේ වසා දැමීම් වලින් වාසි ලබා ගැනීමයි. මූලික වශයෙන් ජාවාස්ක්‍රිප්ට් හි අභ්‍යන්තර ශ්‍රිතයන්ට බාහිර විචල්‍යයන්ට ප්‍රවේශය ඇති බවට අදහස වන්නේ අභ්‍යන්තර විෂය පථයන් පිටත විෂය පථයන් “කොටු” කරන බැවිනි.

වසා දැමීම්

බාහිර ශ්‍රිතය නැවත පැමිණියද අභ්‍යන්තර ශ්‍රිත බාහිර විචල්‍යයන් “රඳවා තබාගෙන” ඒවා ජීවමානව තබා ගනී. මෙය උපයෝගී කර ගැනීම සඳහා, අපි නව විෂය පථයක් සෑදීම, නව විෂය පථය තුළ ප්‍රකාශ කිරීම ilocalසහ භාවිතා කරන අභ්‍යන්තර ශ්‍රිතයක් නැවත ලබා දීම සඳහා තනිකරම එතීමේ ශ්‍රිතයක් නිර්මාණය කර අමතන්නෙමු ilocal(වැඩි විස්තර පහතින්):

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() { //create a new scope using a wrapper function
        var ilocal = i; //capture i into a local var
        return function() { //return the inner function
            console.log("My value: " + ilocal);
        };
    })(); //remember to run the wrapper function
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

එතීෙම් ශ්‍රිතයක් තුළ අභ්‍යන්තර ශ්‍රිතය නිර්මාණය කිරීමෙන් අභ්‍යන්තර ශ්‍රිතයට ප්‍රවේශ විය හැකි පුද්ගලික පරිසරයක් ලබා දෙයි, එය “වසා දැමීම”. මේ අනුව, අපි රැප් ශ්‍රිතය ලෙස හඳුන්වන සෑම අවස්ථාවකම අපි එහි අභ්‍යන්තර පරිසරය සමඟ නව අභ්‍යන්තර ශ්‍රිතයක් නිර්මාණය කරමු ilocal. සුළු ප්‍රශස්තිකරණ කිහිපයක් වෙනත් බොහෝ SO භාවිතා කරන්නන් දුන් අවසාන පිළිතුර ලබා දෙයි:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = wrapper(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}
//creates a separate environment for the inner function
function wrapper(ilocal) {
    return function() { //return the inner function
        console.log("My value: " + ilocal);
    };
}

යාවත්කාලීන කරන්න

ES6 දැන් ප්‍රධාන ධාරාව සමඟ, අපට දැන් නව යතුරුපදය භාවිතා කර letඅවහිර කළ හැකි විචල්‍යයන් නිර්මාණය කළ හැකිය :

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (let i = 0; i < 3; i++) { // use "let" to declare "i"
    funcs[i] = function() {
        console.log("My value: " + i); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) { // we can use "var" here without issue
    funcs[j]();
}

බලන්න දැන් එය කොතරම් පහසුද! වැඩි විස්තර සඳහා මගේ තොරතුරු පදනම් කර ගත් මෙම පිළිතුර බලන්න .


මම කැමතියි ඔබ IIFE ක්‍රමය පැහැදිලි කළ ආකාරය ගැන. මම ඒ ගැන සොයමින් සිටියෙමි. ඔබට ස්තුතියි.
අල්ලා ගත්

4
letසහ constප්‍රධාන වචන භාවිතා කර ජාවාස්ක්‍රිප්ට් හි බ්ලොක් ස්කොපිං වැනි දෙයක් දැන් තිබේ . එය ඇතුළත් කිරීම සඳහා මෙම පිළිතුර පුළුල් කරන්නේ නම්, එය මගේ මතය අනුව ගෝලීය වශයෙන් වඩා ප්‍රයෝජනවත් වනු ඇත.

Iny ටයිනිජියන්ට් විශ්වාසයි, මම ඒ පිළිබඳ තොරතුරු කිහිපයක් එකතු letකර වඩාත් සම්පූර්ණ පැහැදිලි කිරීමක් සම්බන්ධ
කළෙමි

@ woojoo666 ඔබගේ පිළිතුර ද එසේ වැනි පුඩුවක් දෙකක් ප්රත්යාවර්ත URL එක ගේ ඇමතීම සඳහා කටයුතු කළ හැකි: i=0; while(i < 100) { setTimeout(function(){ window.open("https://www.bbc.com","_self") }, 3000); setTimeout(function(){ window.open("https://www.cnn.com","_self") }, 3000); i++ }? (getelementbyid සමග window.open වෙනුවට හැකි () ......)
natty ගැන විකාර කතා

ප්‍රමාද වූ පිළිතුරක් ගැන කණගාටුයි. ඔබගේ උදාහරණයේ කේතය දැනටමත් ක්‍රියාත්මක වන බවක් නොපෙනේ. iඔබගේ කල් ඉකුත් වීමේ කාර්යයන් සඳහා ඔබ භාවිතා නොකරයි , එබැවින් ඔබට වසා දැමීමක් අවශ්‍ය නොවේ
woojoo666

153

ES6 දැන් පුළුල් ලෙස සහාය දක්වන විට, මෙම ප්‍රශ්නයට හොඳම පිළිතුර වෙනස් වී ඇත. මෙම නිශ්චිත අවස්ථාව සඳහා ES6 letසහ constමූල පද සපයයි . වසා දැමීම් සමඟ පටලවා ගැනීම වෙනුවට, අපට letමේ ආකාරයට ලූප් විෂය පථ විචල්‍යයක් සැකසීමට භාවිතා කළ හැකිය :

var funcs = [];

for (let i = 0; i < 3; i++) {          
    funcs[i] = function() {            
      console.log("My value: " + i); 
    };
}

valඉන්පසු එම ලූපයේ නිශ්චිත හැරවීමට විශේෂිත වූ වස්තුවක් වෙත යොමු වන අතර අතිරේක සංවෘත අංකනයකින් තොරව නිවැරදි අගය ලබා දෙනු ඇත. මෙය පැහැදිලිවම මෙම ගැටළුව සැලකිය යුතු ලෙස සරල කරයි.

constletආරම්භක පැවරුමෙන් පසු විචල්‍ය නාමය නව යොමුවකට නැවත යොමු කළ නොහැකි බවට වන අතිරේක සීමාවට සමානය .

බ්‍රව්සර් වල නවතම අනුවාදයන් ඉලක්ක කරගත් අය සඳහා බ්‍රව්සර් සහාය දැන් මෙහි ඇත. const/ letදැනට නවතම ෆයර්ෆොක්ස්, සෆාරි, එජ් සහ ක්‍රෝම් සඳහා සහය දක්වයි. එය නෝඩ් හි ද සහය දක්වයි, බාබෙල් වැනි ගොඩනැඟිලි මෙවලම් වලින් ප්‍රයෝජන ගනිමින් ඔබට ඕනෑම තැනක එය භාවිතා කළ හැකිය. ඔබට වැඩ කරන උදාහරණයක් මෙහි දැකිය හැකිය: http://jsfiddle.net/ben336/rbU4t/2/

මෙහි ලියකියවිලි:

කෙසේ වෙතත්, එඩ්ජ් 14 ට පෙර IE9-IE11 සහ එජ් සහාය දක්වන letනමුත් ඉහත වැරැද්ද ලබා ගන්න (ඒවා iසෑම විටම නව එකක් නිර්මාණය නොකරයි , එබැවින් ඉහත සඳහන් සියලු කාර්යයන් අප භාවිතා කළ ආකාරයටම 3 ට ලොග් වනු ඇත var). 14 වන දාරය අවසානයේ එය නිවැරදිව තේරුම් ගනී.


අවාසනාවකට මෙන්, විශේෂයෙන් ජංගම දුරකථනයේ 'ඉඩ දෙන්න' තවමත් පූර්ණ සහය නොදක්වයි. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
MattC

2
ජුනි 16 වන විට, iOS සෆාරි, ඔපෙරා මිනි සහ සෆාරි 9 හැර අනෙකුත් සියලුම ප්‍රධාන බ්‍රව්සර් අනුවාද වල ඉඩ දෙන්න . සදාහරිත බ්‍රව්සර් එයට සහය දක්වයි. ඉහළ අනුකූලතා මාදිලියක් ක්‍රියාත්මක නොකර අපේක්ෂිත හැසිරීම පවත්වා ගැනීමට බාබෙල් එය නිවැරදිව සම්ප්‍රේෂණය කරයි.
ඩෑන් පැන්ට්රි

An ඩෑන් පැන්ට්රි ඔව් යාවත්කාලීනයක් සඳහා වේලාව ගැන :) යාවත්කාලීන කිරීම්, ලේඛණ සබැඳි සහ වඩා හොඳ අනුකූලතා තොරතුරු ඇතුළත් කිරීම ඇතුළුව වර්තමාන තත්වය වඩාත් හොඳින් පිළිබිඹු කිරීම සඳහා යාවත්කාලීන කරන ලදි.
බෙන් මැකෝමික්

අපගේ කේතය සම්ප්‍රේෂණය කිරීම සඳහා අපි බාබෙල් භාවිතා කරන්නේ මේ නිසා නොවේද? ES6 / 7 සඳහා සහය නොදක්වන බ්‍රව්සර් වලට සිදුවන්නේ කුමක්ද යන්න තේරුම් ගත හැකිය.
පික්සෙල් 67

89

එය පැවසීමේ තවත් ක්‍රමයක් නම්, iඔබේ ශ්‍රිතය තුළ ශ්‍රිතය ක්‍රියාත්මක වන වේලාවට බැඳී ඇති බව මිස ශ්‍රිතය නිර්මාණය කරන වේලාව නොවේ.

ඔබ වසා දැමීම නිර්මාණය කරන විට, i එය බාහිර විෂය පථයේ අර්ථ දක්වා ඇති විචල්‍යයට යොමු කිරීමකි, ඔබ වසා දැමීම නිර්මාණය කළ අවස්ථාවේ දී මෙන් එහි පිටපතක් නොවේ. එය ක්‍රියාත්මක කරන අවස්ථාවේදී ඇගයීමට ලක් කෙරේ.

අනෙක් පිළිතුරු බොහොමයක් ඔබ වෙනුවෙන් වටිනාකම වෙනස් නොකරන වෙනත් විචල්‍යයක් නිර්මාණය කිරීමෙන් වැඩ කිරීමට ක්‍රම සපයයි.

මම හිතුවා මම පැහැදිලි කිරීම සඳහා පැහැදිලි කිරීමක් එකතු කරන්නම් කියලා. විසඳුමක් සඳහා, පෞද්ගලිකව, මම හාර්ටෝ සමඟ යන්නෙමි, මන්ද එය මෙහි ඇති පිළිතුරු වලින් එය වඩාත් ස්වයං පැහැදිලි කිරීමේ ක්‍රමය වන බැවිනි. පළ කරන ලද ඕනෑම කේතයක් ක්‍රියා කරනු ඇත, නමුත් මම නව විචල්‍යයක් (ෆ්‍රෙඩී සහ 1800 ගණන්වල) ප්‍රකාශ කරන්නේ ඇයිද යන්න හෝ අමුතු කාවැද්දූ සංවෘත සින්ටැක්ස් (ඇෆාකර්) තිබේදැයි පැහැදිලි කිරීම සඳහා අදහස් රාශියක් ලිවීමට වඩා වසා දැමීමේ කර්මාන්ත ශාලාවක් තෝරා ගනිමි.


73

ඔබ තේරුම් ගත යුතු දෙය නම් ජාවාස්ක්‍රිප්ට් හි විචල්‍යයන්ගේ විෂය පථය ශ්‍රිතය මත පදනම් වේ. මෙය ඔබට බ්ලොක් විෂය පථයක් ඇති c # යැයි පැවසීමට වඩා වැදගත් වෙනසක් වන අතර, විචල්‍යය සඳහා ඇතුළත එකකට පිටපත් කිරීම ක්‍රියා කරයි.

විචල්‍යයට දැන් ශ්‍රිත විෂය පථය ඇති බැවින්, ඇෆකර්ගේ පිළිතුර වැනි ශ්‍රිතය නැවත ලබා දීම තක්සේරු කරන ශ්‍රිතයක් තුළ එය ඔතා ගැනීම උපක්‍රමය කරයි.

Var වෙනුවට let keyword එකක් ඇත, එමඟින් බ්ලොක් විෂය පථය භාවිතා කිරීමට ඉඩ දෙනු ඇත. එවැනි අවස්ථාවක දී සඳහා විචල්‍යයක් නිර්වචනය කිරීම උපක්‍රමය කරයි. එයින් කියැවෙන්නේ, අනුකූලතාවය නිසා ඉඩ දෙන්න යතුරුපදය ප්‍රායෝගික විසඳුමක් නොවන බවයි.

var funcs = {};

for (var i = 0; i < 3; i++) {
  let index = i; //add this
  funcs[i] = function() {
    console.log("My value: " + index); //change to the copy
  };
}

for (var j = 0; j < 3; j++) {
  funcs[j]();
}


කුමන බ්‍රව්සරයද? මා පැවසූ පරිදි, එයට අනුකූලතා ගැටලු ඇත, ඒ සමඟ මා අදහස් කරන්නේ බරපතල අනුකූලතා ගැටලු ය, IE හි ඉඩ දෙනු ඇතැයි මම නොසිතමි.
eglasius

1
@nickf ඔව්, මෙම යොමු බලන්න developer.mozilla.org/En/New_in_JavaScript_1.7 ... ඉඩ දෙන්න අර්ථ දැක්වීම් කොටස පරීක්ෂා කරන්න, චක්රයක් අභ්යන්තරයේ onclick උදාහරණයක් තිබෙනවා
eglasius

2
icknickf hmm, ඇත්ත වශයෙන්ම ඔබ අනුවාදය පැහැදිලිව සඳහන් කළ යුතුය: <script type = "application / javascript; version = 1.7" /> ... IE සීමාව නිසා මම එය කොතැනකවත් භාවිතා කර නැත, එය එසේ නොවේ ප්‍රායෝගික :(
eglasius

විවිධ අනුවාදයන් සඳහා ඔබට බ්‍රව්සර් සහාය දැක ගත හැකිය es.wikipedia.org/wiki/Javascript
eglasius


61

තාක්ෂණයේ තවත් විචලනයක්, ජෝර්න්ස් (ඇෆාකර්) හා සමාන වන අතර, එය පරාමිතියක් ලෙස සම්මත කරනවාට වඩා ශ්‍රිතය තුළ විචල්‍ය අගය පැවරීමට ඉඩ සලසයි, එය සමහර විට වඩාත් පැහැදිලි විය හැකිය:

var funcs = [];
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() {
        var index = i;
        return function() {
            console.log("My value: " + index);
        }
    })();
}

ඔබ භාවිතා කරන ඕනෑම තාක්‍ෂණය, indexවිචල්‍යය අභ්‍යන්තර ශ්‍රිතයේ ආපසු පිටපතට බැඳී ස්ථිතික විචල්‍යයක් බවට පත්වන බව සලකන්න . එනම්, ඇමතුම් අතර එහි වටිනාකමෙහි වෙනස්කම් ආරක්ෂා වේ. එය ඉතා පහසු විය හැකිය.


ස්තූතියි සහ ඔබේ විසඳුම ක්රියා කරයි. නමුත් මෙය ක්‍රියාත්මක වන්නේ මන්දැයි මම විමසීමට කැමැත්තෙමි, නමුත් varරේඛාව සහ රේඛාව මාරු කිරීම ක්‍රියා returnනොකරන්නේද? ස්තූතියි!
මිඩ්නයිට්

ඔබ ජින් නම් @midnite varසහ returnඑය අභ්යන්තර ශ්රිතය පැමිණීමට පෙර, විචල්ය අනුයුක්ත කරනු නැත.
බෝවන්

55

ජාවාස්ක්‍රිප්ට් හි වසා දැමීම් භාවිතා කිරීමේ පොදු වැරැද්ද මෙය විස්තර කරයි.

ශ්‍රිතයක් නව පරිසරයක් අර්ථ දක්වයි

සලකා බලන්න:

function makeCounter()
{
  var obj = {counter: 0};
  return {
    inc: function(){obj.counter ++;},
    get: function(){return obj.counter;}
  };
}

counter1 = makeCounter();
counter2 = makeCounter();

counter1.inc();

alert(counter1.get()); // returns 1
alert(counter2.get()); // returns 0

සෑම makeCounterවේලාවක්ම ආයාචනා කිරීම සඳහා, {counter: 0}නව වස්තුවක් නිර්මාණය වේ. එසේම, obj නව වස්තුව යොමු කිරීම සඳහා නව පිටපතක් නිර්මාණය වේ. මේ අනුව, counter1සහcounter2 එකිනෙකාගෙන් ස්වාධීන වේ.

ලූප වල වැසීම

ලූපයක වසා දැමීමක් භාවිතා කිරීම උපක්‍රමශීලී ය.

සලකා බලන්න:

var counters = [];

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = {
      inc: function(){obj.counter++;},
      get: function(){return obj.counter;}
    }; 
  }
}

makeCounters(2);

counters[0].inc();

alert(counters[0].get()); // returns 1
alert(counters[1].get()); // returns 1

සිටින බව දැනුම් counters[0]සහ counters[1]නොවන ස්වාධීන. ඇත්ත වශයෙන්ම, ඒවා ක්‍රියාත්මක වන්නේ එකම ආකාරයට යobj !

මෙයට හේතුව obj, ලූපයේ සියලු පුනරාවර්තන හරහා බෙදාගෙන ඇත්තේ එක් පිටපතක් පමණි , සමහර විට කාර්ය සාධන හේතු නිසා ය. {counter: 0}එක් එක් පුනරාවර්තනය තුළ නව වස්තුවක් නිර්මාණය කළද , එකම පිටපතobj නවතම වස්තුව පිළිබඳ සඳහනක් සමඟ යාවත්කාලීන වේ.

විසඳුම වන්නේ වෙනත් සහායක ශ්‍රිතයක් භාවිතා කිරීමයි:

function makeHelper(obj)
{
  return {
    inc: function(){obj.counter++;},
    get: function(){return obj.counter;}
  }; 
}

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = makeHelper(obj);
  }
}

මෙය ක්‍රියාත්මක වන්නේ ශ්‍රිත විෂය පථයේ දේශීය විචල්‍යයන් සෘජුවම මෙන්ම ශ්‍රිත තර්ක විචල්‍යයන් ද ඇතුළත් වූ පසු නව පිටපත් වෙන් කර ඇති බැවිනි.


කුඩා පැහැදිලි කිරීම: ලූපවල වැසීම් පිළිබඳ පළමු උදාහරණයේ දී, කවුන්ටර [0] සහ කවුන්ටර [1] ස්වාධීන නොවන්නේ කාර්ය සාධන හේතු නිසා නොවේ. හේතුව, var obj = {counter: 0};ඕනෑම කේතයක් ක්‍රියාත්මක කිරීමට පෙර ඇගයීමට ලක් කිරීම: MDN var : var ප්‍රකාශන, ඒවා සිදු වූ ඕනෑම තැනක, ඕනෑම කේතයක් ක්‍රියාත්මක කිරීමට පෙර ක්‍රියාවට නංවනු ලැබේ.
චරිඩිමෝස්

51

වඩාත්ම සරල විසඳුම වනුයේ,

භාවිතා කරනවා වෙනුවට:

var funcs = [];
for(var i =0; i<3; i++){
    funcs[i] = function(){
        alert(i);
    }
}

for(var j =0; j<3; j++){
    funcs[j]();
}

එය "2", 3 වතාවක් අනතුරු අඟවයි. මෙයට හේතුව, ලූප් සඳහා නිර්මාණය කරන ලද නිර්නාමික ශ්‍රිතයන්, එකම වසා දැමීමක් බෙදා ගැනීම සහ එම වසා දැමීමේදී එහි අගය iසමාන වේ. හවුල් වසා දැමීම වැළැක්වීමට මෙය භාවිතා කරන්න:

var funcs = [];
for(var new_i =0; new_i<3; new_i++){
    (function(i){
        funcs[i] = function(){
            alert(i);
        }
    })(new_i);
}

for(var j =0; j<3; j++){
    funcs[j]();
}

මෙහි ඇති අදහස නම්, for for loop හි මුළු සිරුරම a සමඟ සංයුක්ත කිරීමයි IIFE (ක්ෂණිකව ආයාචනය කරන ලද ක්‍රියාකාරී ප්‍රකාශනය) සංයුක්තnew_i කර පරාමිතියක් ලෙස සම්මත කර එය අල්ලා ගැනීමයි i. නිර්නාමික ශ්‍රිතය වහාම ක්‍රියාත්මක වන බැවින්i තුළ අර්ථ දක්වා ඇති සෑම ශ්‍රිතයක් සඳහාම අගය වෙනස් වේ.

මෙම ගැටළුව එවැනි ගැටලුවකට ගැලපෙන බව පෙනේ, මන්ද මෙම ගැටලුවෙන් පීඩා විඳින මුල් කේතයේ අවම වෙනස්කම් අවශ්‍ය වනු ඇත. ඇත්ත වශයෙන්ම, මෙය සැලසුම අනුව ය, එය කිසිසේත්ම ගැටලුවක් නොවිය යුතුය!


2
පොතක සමාන දෙයක් වරක් කියවන්න. ඔබත් දැනට පවතින කේතය ස්පර්ශ කිරීමට අවශ්‍ය නැති නිසා (ඔබ) ඔබ එය කළේ ඇයිද යන්න පැහැදිලි වන හෙයින්, ඔබ ස්වයං ඇමතුම් ක්‍රියාකාරී රටාව ඉගෙන ගත් පසු: එම විචල්‍යය අලුතින් සාදන ලද විෂය පථය.
ඩෑන්මන්

1
An ඩන්මන් ස්තූතියි. ජාවාස්ක්‍රිප්ට් හි බ්ලොක් මට්ටමේ විචල්‍ය විෂය පථය නොමැතිකම සමඟ කටයුතු කිරීමට ස්වයං ඇමතුම් නිර්නාමික කාර්යයන් ඉතා හොඳ ක්‍රමයකි.
කෙමාල් ğ

3
ස්වයං-ඇමතුම් හෝ ස්වයං-ආයාචනය මෙම තාක්ෂණය සඳහා සුදුසු යෙදුම නොවේ, IIFE (ක්ෂණිකව ආයාචනය කරන ලද ක්‍රියාකාරී ප්‍රකාශනය) වඩාත් නිවැරදිව. Ref: benalman.com/news/2010/11/…
jherax

32

මෙම කෙටි එක උත්සාහ කරන්න

  • අරාවක් නැත

  • ලූප සඳහා අමතර කිසිවක් නැත


for (var i = 0; i < 3; i++) {
    createfunc(i)();
}

function createfunc(i) {
    return function(){console.log("My value: " + i);};
}

http://jsfiddle.net/7P6EN/


1
ඔබේ විසඳුම ප්‍රතිදානය නිවැරදි බව පෙනේ, නමුත් එය අනවශ්‍ය ලෙස කාර්යයන් භාවිතා කරයි, නිමැවුම console.log පමණක් නොවන්නේ ඇයි? මුල් ප්‍රශ්නය වන්නේ එකම වසා දැමීමක් ඇති නිර්නාමික කාර්යයන් නිර්මාණය කිරීමයි. ගැටළුව වූයේ, ඔවුන්ට තනි වසා දැමීමක් ඇති බැවින්, i හි අගය ඒ සෑම එකක් සඳහාම සමාන වේ. මම හිතනවා ඔබට එය ලැබුණා කියලා.
Kemal Dağ

31

භාවිතා කරන සරල විසඳුමක් මෙන්න forEach(IE9 වෙත නැවත ක්‍රියා කරයි):

var funcs = [];
[0,1,2].forEach(function(i) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
})
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

මුද්‍රණ:

My value: 0
My value: 1
My value: 2

28

OP පෙන්වා ඇති කේතය සමඟ ඇති ප්‍රධාන ගැටළුව iවන්නේ දෙවන ලූපය තෙක් කිසි විටෙක කියවීම නොවේ. නිරූපණය කිරීමට, කේතයේ දෝෂයක් දැකීම සිතන්න

funcs[i] = function() {            // and store them in funcs
    throw new Error("test");
    console.log("My value: " + i); // each should log its value.
};

funcs[someIndex]ක්‍රියාත්මක වන තුරු දෝෂය ඇත්ත වශයෙන්ම සිදු නොවේ (). මෙම තර්කනයම භාවිතා කරමින්, iමෙම ලක්ෂ්‍යය තෙක් එහි වටිනාකම ද එකතු නොවන බව පෙනේ . මුල් ලූපය අවසන් වූ පසු, තත්වය අසාර්ථක වන අතර ලූපය අවසන් වන අගයට එය i++ගෙන එයි . මෙම අවස්ථාවෙහිදී, භාවිතා වන්නේ කවදාද , සහi3i < 3i3funcs[someIndex]()i ඇගයීමට ලක් වේ, එය 3 වන - සෑම අවස්ථාවකදීම.

මෙය පසුකර යාමට iනම්, එය හමු වූ විට ඔබ ඇගයීමට ලක් කළ යුතුය . මෙය දැනටමත් ස්වරූපයෙන් සිදුවී ඇති බව සලකන්නfuncs[i] (අද්විතීය දර්ශක 3 ක් ඇති තැන). මෙම අගය ග්‍රහණය කර ගැනීමට ක්‍රම කිහිපයක් තිබේ. එකක් නම් එය දැනටමත් මෙහි ආකාර කිහිපයකින් පෙන්වා ඇති ශ්‍රිතයකට පරාමිතියක් ලෙස යැවීමයි.

තවත් විකල්පයක් නම් විචල්‍යයට ඉහළින් වැසීමට හැකි ශ්‍රිත වස්තුවක් තැනීමයි. එය එසේ කළ හැකිය

jsFiddle Demo

funcs[i] = new function() {   
    var closedVariable = i;
    return function(){
        console.log("My value: " + closedVariable); 
    };
};

24

ජාවාස්ක්‍රිප්ට් ක්‍රියාකාරීත්වය ප්‍රකාශ කිරීමෙන් පසු ඔවුන්ට ප්‍රවේශ විය හැකි විෂය පථය “සමීප” වන අතර එම විෂය පථයේ විචල්‍යයන් ලෙස වුවද එම විෂය පථයට ප්‍රවේශය රඳවා ගනී.

var funcs = []

for (var i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

ඉහත අරාවෙහි ඇති සෑම ශ්‍රිතයක්ම ගෝලීය විෂය පථයට වඩා වසා දමයි (ගෝලීය, එය ප්‍රකාශිත විෂය පථය නිසා)

පසුකාලීනව එම කාර්යයන් iගෝලීය විෂය පථයේ වඩාත්ම වර්තමාන අගය සටහන් කර ඇත. එය වසා දැමීමේ මැජික් සහ කලකිරීමයි.

"ජාවාස්ක්‍රිප්ට් කාර්යයන් ඒවා ප්‍රකාශයට පත් කර ඇති විෂය පථයට වඩා සමීප වන අතර එම විෂය පථය තුළ විචල්‍ය අගයන් වෙනස් වුවද එම විෂය පථයට ප්‍රවේශය රඳවා ගනී."

letඒ වෙනුවට භාවිතා කිරීම varමඟින් forලූපය ක්‍රියාත්මක වන සෑම අවස්ථාවකම නව විෂය පථයක් නිර්මාණය කිරීමෙන් එක් එක් ශ්‍රිතය අවසන් වීමට වෙනම විෂය පථයක් නිර්මාණය කරයි. වෙනත් විවිධ ශිල්පීය ක්‍රම අතිරේක කාර්යයන් සමඟ එකම දේ කරයි.

var funcs = []

for (let i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

( letවර්ගයන් විචල්ය scoped වාරණ. කාණ්ඩයන් කිරීමට සඟල මගින් වන අතර, නමුත් පුඩුවක් සඳහා ආරම්භය විචල්ය පිළිබඳ පැමිණිල්ලේ දී, iඅපගේ නඩුවේ, සඟල වරහන් දී ප්රකාශයට පත් කරන බවට සැලකේ.)


1
මෙම පිළිතුර කියවන තෙක් මෙම සංකල්පය තේරුම් ගැනීමට මම වෙහෙසුණා. එය සැබවින්ම වැදගත් කරුණක් ස්පර්ශ කරයි - එහි වටිනාකම iගෝලීය විෂය පථයට සකසා ඇත. forලූපය ක්‍රියාත්මක වීම අවසන් වූ විට , එහි ගෝලීය අගය iදැන් 3 වේ. එබැවින්, එම ශ්‍රිතය අරාවෙහි ආයාචනා කරන සෑම අවස්ථාවකම (භාවිතා කරමින්, කියමින් funcs[j]), iඑම ශ්‍රිතයේ ගෝලීය iවිචල්‍යය (එය 3) යොමු කරයි.
මොඩර්මෝ

14

විවිධ විසඳුම් කියවීමෙන් පසුව, එම විසඳුම් ක්‍රියාත්මක වීමට හේතුව විෂය පථ දාමය පිළිබඳ සංකල්පය මත රඳා පැවතීමයි . ක්‍රියාත්මක කිරීමේදී ජාවාස්ක්‍රිප්ට් විචල්‍යයක් නිරාකරණය කරන ආකාරය එයයි.

  • සෑම ශ්‍රිත අර්ථ දැක්වීමක් විසින්ම ප්‍රකාශයට පත් කරන ලද සියලුම දේශීය විචල්‍යයන්ගෙන් varසහ එය විසින් ප්‍රකාශයට පත් කරන ලද විෂය පථයක් සාදයි arguments.
  • වෙනත් (පිටත) ශ්‍රිතයක් තුළ අපට අභ්‍යන්තර ශ්‍රිතය අර්ථ දක්වා ඇත්නම්, මෙය දාමයක් සාදයි, එය ක්‍රියාත්මක කිරීමේදී භාවිතා වේ
  • ශ්‍රිතයක් ක්‍රියාත්මක වූ විට, ධාවන කාලය විෂය පථ දාමය සෙවීමෙන් විචල්‍යයන් ඇගයීමට ලක් කරයි . දාමයේ එක්තරා ස්ථානයක විචල්‍යයක් සොයාගත හැකි නම්, එය සෙවීම නවතා එය භාවිතා කරනු ඇත, එසේ නොමැති නම් ගෝලීය විෂය පථයට අයත් වන තෙක් එය දිගටම පවතී window.

ආරම්භක කේතයේ:

funcs = {};
for (var i = 0; i < 3; i++) {         
  funcs[i] = function inner() {        // function inner's scope contains nothing
    console.log("My value: " + i);    
  };
}
console.log(window.i)                  // test value 'i', print 3

funcsක්‍රියාත්මක වූ විට, විෂය පථය වනු ඇත function inner -> global. විචල්‍යය iසොයාගත නොහැකි බැවින් function inner( varතර්ක ලෙස භාවිතා කිරීම හෝ ප්‍රකාශ කිරීම සම්මත කර නැත), iගෝලීය විෂය පථයේ වටිනාකම අවසානයේ සොයා ගන්නා තෙක් එය දිගටම සෙවීම සිදු කරයි window.i.

පිටත කාර්යය එය ඔතන විසින් එක්කෝ පැහැදිලිව සහකාරියක් ශ්රිතයක් අර්ථ දැක්විය වැනි harto කළේ හෝ වැනි නිර්නාමික ක්රියාව භාවිත Bjorn කළේ:

funcs = {};
function outer(i) {              // function outer's scope contains 'i'
  return function inner() {      // function inner, closure created
   console.log("My value: " + i);
  };
}
for (var i = 0; i < 3; i++) {
  funcs[i] = outer(i);
}
console.log(window.i)          // print 3 still

funcsක්‍රියාත්මක වූ විට, දැන් විෂය පථය වනු ඇත function inner -> function outer. මෙම වේලාව iපිටත ශ්‍රිතයේ විෂය පථයෙන් සොයා ගත හැකි අතර එය for for loop හි 3 වතාවක් ක්‍රියාත්මක වේ, සෑම අවස්ථාවකම අගය iනිවැරදිව බැඳී ඇත. window.iඅභ්‍යන්තරය ක්‍රියාත්මක කිරීමේදී එහි අගය භාවිතා නොකරයි .

වැඩි විස්තර මෙතැනින් සොයාගත හැකිය. මෙහි
ඇති දේ ලෙස ලූපය වසා දැමීමේ පොදු වැරැද්ද මෙන්ම අපට වසා දැමීම අවශ්‍ය වන්නේ ඇයි සහ කාර්ය සාධනය සලකා බැලීම ද ඇතුළත් වේ.


අපි මෙම කේත නියැදිය යථාර්ථවාදීව ලියන්නේ කලාතුරකිනි, නමුත් මූලික දේ තේරුම් ගැනීමට එය හොඳ උදාහරණයක් සපයයි. අපගේ මනසෙහි විෂය පථය සහ ඒවා එකට බැඳ ඇති ආකාරය බැලූ විට, Array.prototype.forEach(function callback(el) {})ස්වාභාවිකවම වැනි වෙනත් 'නවීන' ක්‍රම ක්‍රියාත්මක වන්නේ මන්දැයි බැලීමට වඩාත් පැහැදිලිය : ස්වාභාවිකවම සම්මත වූ ඇමතුම ස්වාභාවිකවම සම්මත වන අතර, එක් එක් පුනරාවර්තනය තුළ නිවැරදිව බැඳී ඇති එල් සමඟ එතීමේ විෂය පථය සාදයි forEach. එබැවින් el
ඇමතුමෙහි

13

ES6 බ්ලොක් මට්ටමේ විෂය පථයේ නව අංග සමඟ කළමනාකරණය කරනු ලැබේ:

var funcs = [];
for (let i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (let j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

OP හි ප්‍රශ්නයේ කේතය වෙනුවට ආදේශ කරනු letලැබේ var.


constඑකම ප්‍රති result ලය සපයන අතර විචල්‍යයක අගය වෙනස් නොවන විට භාවිතා කළ යුතුය. කෙසේ වෙතත්, constfor for loop හි ආරම්භක භාවිතය ෆයර්ෆොක්ස් හි වැරදි ලෙස ක්‍රියාත්මක කර ඇති අතර එය තවමත් සවි කර නොමැත. බ්ලොක් එක ඇතුළත ප්‍රකාශයට පත් කරනවා වෙනුවට එය බ්ලොක් එකෙන් පිටත ප්‍රකාශයට පත් කරන අතර එමඟින් විචල්‍යයට නැවත ප්‍රකාශනයක් සිදු වන අතර එමඟින් දෝෂයක් ඇති වේ. ආරම්භක letඇතුළත භාවිතය ෆයර්ෆොක්ස් හි නිවැරදිව ක්‍රියාත්මක වන බැවින් එහි කරදර වීමට අවශ්‍ය නැත.

10

forEachදේශීය විචල්‍යයන් භාවිතා කිරීමෙන් (නැවත) වඩා හොඳින් වළක්වා ගැනීම සඳහා ශ්‍රිතය භාවිතා කිරීමට කිසිවෙකු තවමත් යෝජනා නොකිරීම මට පුදුමයකි . ඇත්ත වශයෙන්ම, මම for(var i ...)මේ හේතුව නිසා තවදුරටත් භාවිතා නොකරමි .

[0,2,3].forEach(function(i){ console.log('My value:', i); });
// My value: 0
// My value: 2
// My value: 3

// forEachසිතියම වෙනුවට භාවිතා කිරීමට සංස්කරණය කරන ලදි .


3
.forEach()ඔබ ඇත්ත වශයෙන්ම කිසිවක් සිතියම් ගත නොකරන්නේ නම් වඩා හොඳ විකල්පයක් වන අතර ඩැරල් යෝජනා කළේ ඔබ පළ කිරීමට මාස 7 කට පෙර, එබැවින් පුදුම වීමට කිසිවක් නැත.
ජේ.එල්.රිෂේ

මෙම ප්‍රශ්නය අරාවකට වඩා ලූපයක් ගැන නොවේ
ජෙරැක්ස්

හොඳයි, ඔහුට අවශ්‍ය වන්නේ ශ්‍රිත සමූහයක් නිර්මාණය කිරීමට ය, මෙම උදාහරණය ගෝලීය විචල්‍යයකට සම්බන්ධ නොවී එය කරන්නේ කෙසේදැයි පෙන්වයි.
ක්‍රිස්ටියන් ලෑන්ඩ්ග්‍රන්

9

මෙම ප්‍රශ්නය සැබවින්ම ජාවාස්ක්‍රිප්ට් ඉතිහාසය පෙන්වයි! දැන් අපට ඊතල ශ්‍රිත සමඟ අවහිර කිරීම් වළක්වා ගත හැකි අතර වස්තු ක්‍රම භාවිතයෙන් DOM නෝඩ් වලින් කෙලින්ම ලූප හැසිරවිය හැකිය.

const funcs = [1, 2, 3].map(i => () => console.log(i));
funcs.map(fn => fn())

const buttons = document.getElementsByTagName("button");
Object
  .keys(buttons)
  .map(i => buttons[i].addEventListener('click', () => console.log(i)));
<button>0</button><br>
<button>1</button><br>
<button>2</button>


8

ඔබේ මුල් උදාහරණය ක්‍රියාත්මක නොවීමට හේතුව නම්, ඔබ ලූපය තුළ සාදන ලද සියලුම වසා දැමීම් එකම රාමුවක් ගැන සඳහන් කිරීමයි. එක් iවිචල්‍යයක් සහිත එක් වස්තුවක් මත ක්‍රම 3 ක් තිබීම . ඒවා සියල්ලම එකම අගයක් මුද්‍රණය කරයි.


8

පළමුවෙන්ම, මෙම කේතයේ ඇති වැරැද්ද තේරුම් ගන්න:

var funcs = [];
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

මෙන්න funcs[]අරාව ආරම්භ කරන විට, iවැඩි කරන විට, funcsඅරාව ආරම්භ කර ඇති අතර funcඅරාවේ ප්‍රමාණය 3 බවට පත්වේ i = 3,. දැන් funcs[j]()කැඳවූ විට, එය නැවතත් විචල්‍යය භාවිතා කරයි i, එය දැනටමත් 3 දක්වා වැඩි කර ඇත.

දැන් මෙය විසඳීම සඳහා අපට බොහෝ විකල්ප තිබේ. ඒවායින් දෙකක් පහත දැක්වේ:

  1. අපට නව විචල්‍යයක් සමඟ ආරම්භ iකිරීමට letහෝ ආරම්භ කිරීමට හා එය සමාන කළ හැකිය. එබැවින් ඇමතුම ලබා දෙන විට, භාවිතා කරනු ඇති අතර එහි විෂය පථය ආරම්භ කිරීමෙන් පසුව අවසන් වේ. ඇමතීම සඳහා, නැවත ආරම්භ කරනු ලැබේ:indexletiindexindex

    var funcs = [];
    for (var i = 0; i < 3; i++) {          
        let index = i;
        funcs[i] = function() {            
            console.log("My value: " + index); 
        };
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }
  2. වෙනත් විකල්පයක් tempFuncවනුයේ සත්‍ය ශ්‍රිතය නැවත ලබා දෙන a හඳුන්වා දීමයි :

    var funcs = [];
    function tempFunc(i){
        return function(){
            console.log("My value: " + i);
        };
    }
    for (var i = 0; i < 3; i++) {  
        funcs[i] = tempFunc(i);                                     
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }

8

වසා දැමීමේ ව්‍යුහය භාවිතා කරන්න , මෙය ඔබේ අමතර ලූප අඩු කරයි. ඔබට එය ලූපයක් සඳහා තනි ආකාරයකින් කළ හැකිය:

var funcs = [];
for (var i = 0; i < 3; i++) {     
  (funcs[i] = function() {         
    console.log("My value: " + i); 
  })(i);
}

7

අපි ප්‍රකාශ කරන්නෙමු, ඔබ ප්‍රකාශ කරන විට සත්‍ය වශයෙන්ම සිදුවන්නේ කුමක්ද varසහ let එකින් එක.

Case1 : භාවිතා කිරීමvar

<script>
   var funcs = [];
   for (var i = 0; i < 3; i++) {
     funcs[i] = function () {
        debugger;
        console.log("My value: " + i);
     };
   }
   console.log(funcs);
</script>

දැන් F12 එබීමෙන් ඔබගේ ක්‍රෝම් කොන්සෝල කවුළුව විවෘත කර පිටුව නැවුම් කරන්න. අරාව තුළ ඇති සෑම කාර්යයන් 3 ක්ම වියදම් කරන්න .ඔබට දේපලක් පෙනෙනු ඇත .එය පුළුල් කරන්න. එක් අරාව වස්තුවක් ඔබට පෙනෙනු ඇත , එය පුළුල් කරන්න. 3 වන අගය ඇති වස්තුවට ප්‍රකාශිත දේපලක් ඔබ සොයා ගනු ඇත .[[Scopes]]"Global"'i'

රූප විස්තරය මෙහි ඇතුළත් කරන්න

රූප විස්තරය මෙහි ඇතුළත් කරන්න

නිගමනය:

  1. 'var'ශ්‍රිතයකට පිටතින් භාවිතා කරමින් ඔබ විචල්‍යයක් ප්‍රකාශ කරන විට , එය ගෝලීය විචල්‍යයක් බවට පත්වේ (ඔබට යතුරු ලියනය කිරීමෙන් iහෝ window.iකොන්සෝල කවුළුවකින් පරීක්ෂා කළ හැකිය . එය 3 නැවත පැමිණේ).
  2. ඔබ ප්‍රකාශ කළ නාමික ශ්‍රිතය ඔබ ශ්‍රිතයන් කැඳවන්නේ නැත්නම් ශ්‍රිතය තුළ ඇති අගය අමතන්නේ නැත.
  3. ඔබ ශ්‍රිතය ඉල්ලා සිටින විට, console.log("My value: " + i)එහි Globalවස්තුවෙන් අගය ගෙන ප්‍රති .ලය පෙන්වයි.

CASE2: ඉඩ භාවිතා කිරීම

දැන් වෙනුවට 'var'සමග'let'

<script>
    var funcs = [];
    for (let i = 0; i < 3; i++) {
        funcs[i] = function () {
           debugger;
           console.log("My value: " + i);
        };
    }
    console.log(funcs);
</script>

එකම දේ කරන්න, විෂය පථ වෙත යන්න. දැන් ඔබ වස්තූන් දෙකක් පෙනෙනු ඇත "Block"හා "Global". දැන් Blockවස්තුව පුළුල් කරන්න , එවිට ඔබට 'i' යන්න අර්ථ දක්වා ඇති අතර අමුතුම දෙය නම්, සෑම ශ්‍රිතයක් සඳහාම අගය iවෙනස් නම් (0, 1, 2).

රූප විස්තරය මෙහි ඇතුළත් කරන්න

නිගමනය:

ඔබ භාවිතා විචල්ය ප්රකාශ කරන විට 'let'පවා කාර්යය පිටත නමුත් පුඩුවක් තුල, මෙම විචල්ය වූ ගෝලීය වෙනස් විය නොහැකි, එය වනු ඇත Blockහේතුව only.That එම උත්සවය සඳහා පමණක් ලබා ගත හැකි වන මට්ටමින් විචල්ය, අපි වටිනාකම හැරෙනවා iවිවිධ එක් එක් ශ්‍රිතය සඳහා අපි ශ්‍රිතයන් කැඳවන විට.

වඩාත් සමීපව ක්‍රියා කරන ආකාරය පිළිබඳ වැඩි විස්තර සඳහා කරුණාකර නියම වීඩියෝ නිබන්ධනය https://youtu.be/71AtaJpJHw0 හරහා යන්න.


4

විමසුම්- js (*) වැනි දත්ත ලැයිස්තු සඳහා ඔබට ප්‍රකාශන මොඩියුලයක් භාවිතා කළ හැකිය . මෙම තත්වයන් තුළ මම පෞද්ගලිකව ප්‍රකාශන ප්‍රවේශයක් අඩු පුදුමයක් ලෙස දකිමි

var funcs = Query.range(0,3).each(function(i){
     return  function() {
        console.log("My value: " + i);
    };
});

එවිට ඔබට ඔබේ දෙවන ලූපය භාවිතා කර අපේක්ෂිත ප්‍රති result ලය ලබා ගත හැකිය, නැතහොත් ඔබට කළ හැකිය

funcs.iterate(function(f){ f(); });

.


1
පහත් ඡන්දය පිළිබඳ පැහැදිලි කිරීමකට මම කැමතියි. කේතය අත ළඟ ඇති ගැටළුව විසඳයි. කේතය වැඩිදියුණු කළ හැකි ආකාරය දැන ගැනීම
වටී

1
කුමක්ද Query.range(0,3)? මෙය මෙම ප්‍රශ්නය සඳහා වන ටැග් වල කොටසක් නොවේ. ඊට අමතරව, ඔබ තෙවන පාර්ශවීය පුස්තකාලයක් භාවිතා කරන්නේ නම්, ඔබට ප්‍රලේඛනයේ සබැඳිය ලබා දිය හැකිය.
ජෙරාක්ස්

1
he ජෙරාක්ස් ඒවා හෝ පැහැදිලිවම පැහැදිලි කිරීම්. අදහස් දැක්වීමට ස්තූතියි. මට දැනටමත් දිවුරුම් දෙන්න තිබුණා දැනටමත් සබැඳියක් තියෙනවා කියලා. මම හිතන විදියට මේ පෝස්ට් එක තේරුමක් නැති දෙයක්. එය වළක්වා ගැනීමේ මගේ මුලික අදහස වූයේ මම මගේම පුස්තකාලයක් භාවිතා කිරීමට උත්සාහ නොකිරීම නිසා ප්‍රකාශන අදහස වැඩි වීමයි. කෙසේ වෙතත්, පසු විපරමේදී මම සබැඳිය තිබිය යුතු බවට සම්පුර්ණයෙන්ම එකඟ වෙමි
රූන් එෆ්එස්

4

forEachව්‍යාජ පරාසයක් නිර්මාණය කිරීම සමඟ එයම වසා ඇති ශ්‍රිතයක් භාවිතා කිරීමට මම කැමැත්තෙමි :

var funcs = [];

new Array(3).fill(0).forEach(function (_, i) { // creating a range
    funcs[i] = function() {            
        // now i is safely incapsulated 
        console.log("My value: " + i);
    };
});

for (var j = 0; j < 3; j++) {
    funcs[j](); // 0, 1, 2
}

එය වෙනත් භාෂාවල පරාසයන්ට වඩා කැත ලෙස පෙනේ, නමුත් IMHO වෙනත් විසඳුම් වලට වඩා භයානක ය.


එයට වඩා කැමති කුමක්ද? මෙය වෙනත් පිළිතුරකට පිළිතුරු වශයෙන් අදහස් දැක්වීමක් ලෙස පෙනේ. එය කිසිසේත්ම සත්‍ය ප්‍රශ්නයට ආමන්ත්‍රණය නොකරයි (ඔබ ශ්‍රිතයක් පවරා නැති නිසා, පසුව ඕනෑම තැනක කැඳවීමට).
ක්වෙන්ටින්

එය හරියටම සඳහන් කළ ගැටලුවට සම්බන්ධයි: වසා දැමීමේ ගැටළු නොමැතිව ආරක්ෂිතව ක්‍රියා කරන්නේ කෙසේද
Rax Wunter

දැන් එය පිළිගත් පිළිතුරට වඩා සැලකිය යුතු ලෙස වෙනස් බවක් නොපෙනේ.
ක්වෙන්ටින්

නැත. පිළිගත් පිළිතුරෙහි "යම් අරාවක්" භාවිතා කිරීමට යෝජනා කර ඇත, නමුත් අපි පිළිතුරේ පරාසයක් සමඟ ගනුදෙනු කරන්නෙමු, එය සම්පූර්ණයෙන්ම වෙනස් දේවල්, අවාසනාවකට js හි හොඳ විසඳුමක් නොමැති නිසා මගේ පිළිතුර විසඳීමට උත්සාහ කරයි ප්‍රශ්නය හොඳ සහ ප්‍රායෝගික ආකාරයකින්
රැක්ස් වුන්ටර්

@ ක්වෙන්ටින් අවම කිරීමට පෙර විසඳුම සොයා බැලීමට මම නිර්දේශ කරමි
රැක්ස් වුන්ටර්

4

තවත් විසඳුමක්: වෙනත් ලූපයක් නිර්මාණය කරනවා වෙනුවට this, ආපසු එන ශ්‍රිතයට බැඳ තබන්න .

var funcs = [];

function createFunc(i) {
  return function() {
    console.log('My value: ' + i); //log value of i.
  }.call(this);
}

for (var i = 1; i <= 5; i++) {  //5 functions
  funcs[i] = createFunc(i);     // call createFunc() i=5 times
}

මෙය බන්ධනය කිරීමෙන් ගැටළුව ද විසඳයි.


3

බොහෝ විසඳුම් නිවැරදි යැයි පෙනුනද, එය Curryingමෙවැනි තත්වයන් සඳහා ක්‍රියාකාරී ක්‍රමලේඛන සැලසුම් රටාවක් ලෙස හැඳින්වෙන බව ඔවුන් සඳහන් නොකරයි . බ්‍රව්සරය මත පදනම්ව බන්ධනයට වඩා 3-10 ගුණයක් වේගවත්.

var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = curryShowValue(i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();                      // and now let's run each one to see
}

function curryShowValue(i) {
  return function showValue() {
    console.log("My value: " + i);
  }
}

විවිධ බ්‍රව්සර්වල කාර්ය සාධනය බලන්න .


Iny ටයිනිජියන්ට් ශ්‍රිතය නැවත ලබා දීමේ උදාහරණය තවමත් කාර්ය සාධනය සඳහා ප්‍රශස්තිකරණය කර ඇත. සියලුම ජාවාස්ක්‍රිප්ට් බ්ලොග් කරුවන් මෙන් මම ඊතල ක්‍රියාකාරිත්ව කලාපයට පනින්නේ නැත. ඒවා සිසිල් හා පිරිසිදු පෙනුමක් ඇති නමුත් පූර්ව නිශ්චිත ශ්‍රිත භාවිතා කිරීම වෙනුවට පේළිගත කිරීමේ කාර්යයන් ප්‍රවර්ධනය කරයි. මෙය උණුසුම් ස්ථානවල පැහැදිලි නොවන උගුලක් විය හැකිය. තවත් ගැටළුවක් වන්නේ ඒවා හුදෙක් සින්ටැක්ටික් සීනි නොවන නිසා ඒවා අනවශ්‍ය බන්ධන ක්‍රියාත්මක කරන නිසා එතීම වසා දැමීමයි.
පවෙල්

2
අනාගත පා readers කයන්ට අවවාදයයි: මෙම පිළිතුර ව්‍යංජන යන යෙදුම සාවද්‍ය ලෙස අදාළ වේ . "ව්‍යංජන යනු ඔබ තර්ක කිහිපයකට සහභාගී වන ශ්‍රිත මාලාවකට බහුවිධ තර්ක ගෙන යන ශ්‍රිතයක් බිඳ දැමීමයි." . මෙම කේතය එවැනි කිසිවක් නොකරයි. ඔබ මෙහි කර ඇත්තේ පිළිගත් පිළිතුරෙන් කේතය රැගෙන යාම, සමහර දේවල් එහා මෙහා ගෙනයාම, ශෛලිය වෙනස් කිරීම සහ ටිකක් නම් කිරීම, පසුව එය ව්‍යංජන ලෙස හඳුන්වන්න, එය නිශ්චිතවම නොවේ.

3

ඔබේ කේතය ක්‍රියා නොකරයි, මන්ද එය කරන්නේ එයයි:

Create variable `funcs` and assign it an empty array;  
Loop from 0 up until it is less than 3 and assign it to variable `i`;
    Push to variable `funcs` next function:  
        // Only push (save), but don't execute
        **Write to console current value of variable `i`;**

// First loop has ended, i = 3;

Loop from 0 up until it is less than 3 and assign it to variable `j`;
    Call `j`-th function from variable `funcs`:  
        **Write to console current value of variable `i`;**  
        // Ask yourself NOW! What is the value of i?

දැන් ප්‍රශ්නය නම්, iශ්‍රිතය හැඳින්වූ විට විචල්‍යයේ වටිනාකම කුමක්ද? පළමු ලූපය කොන්දේසිය සමඟ නිර්මාණය කර ඇති නිසා i < 3, තත්වය අසත්‍ය වූ විට එය වහාම නතර වේ, එබැවින් එය එසේ වේ i = 3.

ඔබ තේරුම් ගත යුතුයි, ඔබේ කාර්යයන් නිර්මාණය කරන විට, ඒවායේ කේත කිසිවක් ක්‍රියාත්මක නොවන විට, එය සුරකින ලද්දේ පසුව පමණි. එබැවින් ඔවුන් පසුව කැඳවූ විට, පරිවර්තකයා ඒවා ක්‍රියාත්මක කර අසයි: "එහි වර්තමාන වටිනාකම iකුමක්ද?"

එබැවින්, ඔබේ ඉලක්කය වන්නේ පළමුව iක්‍රියාකාරීත්වයේ වටිනාකම සුරැකීම සහ ඉන් පසුව පමණක් ශ්‍රිතය සුරැකීමයි funcs. මෙය උදාහරණයක් ලෙස මේ ආකාරයෙන් කළ හැකිය:

var funcs = [];
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function(x) {            // and store them in funcs
        console.log("My value: " + x); // each should log its value.
    }.bind(null, i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

මේ ආකාරයට, සෑම ශ්‍රිතයකටම එයටම විචල්‍යයක් ඇති xඅතර අපි මෙය එක් එක් පුනරාවර්තනයේ xඅගයට iසකසමු.

මෙය මෙම ගැටළුව විසඳීමට ඇති විවිධ ක්‍රමවලින් එකක් පමණි.


3
var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = function(param) {          // and store them in funcs
    console.log("My value: " + param); // each should log its value.
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j](j);                      // and now let's run each one to see with j
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.