JavaScript Patterns 读书笔记(一)
一.Global
全局域中的this = window.myglobal = "hello"; // antipatternconsole.log(myglobal); // "hello"console.log(window.myglobal); // "hello"console.log(window["myglobal"]); // "hello"console.log(this.myglobal); // "hello", 全局域中的this = window.??Another antipattern that creates implied globals is to chain assignments??as part of a var declaration. In the following snippet, a is local but b??becomes global, which is probably not what you meant to do:
// antipattern, do not usefunction foo() {var a = b = 0;// ...}?
var a = (b = 0);?
function foo() {var a, b;// ...a = b = 0; // both local}?Side Effects When Forgetting var:
// define three globalsvar global_var = 1;global_novar = 2; // antipattern(function () {global_fromfunc = 3; // antipattern}());// attempt to deletedelete global_var; // falsedelete global_novar; // truedelete global_fromfunc; // true// test the deletiontypeof global_var; // "number"typeof global_novar; // "undefined"typeof global_fromfunc; // "undefined"?? ?In ES5 strict mode, assignments to undeclared variables (such as the two antipatterns in the preceding snippet) will throw an error.
// antipatternmyname = "global"; // global variablefunction func() {alert(myname); // "undefined"var myname = "local";alert(myname); // "local"}func();?? ?In this example, you might expect that the first alert() will prompt “global” and the?second will prompt “local.” It’s a reasonable expectation because, at the time of the?first alert, myname was not declared and therefore the function should probably “see”?the global myname. But that’s not how it works. The first alert will say “undefined”?because myname is considered declared as a local variable to the function. (Although the?declaration comes after.) All the variable declarations get hoisted to the top of the?function. Therefore to avoid this type of confusion, it’s best to declare upfront all variables?you intend to use.?The preceding code snippet will behave as if it were implemented like so:
myname2 = "global"; // global variablefunction func_fixed() {var myname2; // same as -> var myname = undefined;alert(myname2); // "undefined"myname2 = "local";alert(myname2); // "local"}func_fixed();?for Loops
// sub-optimal loopfor (var i = 0; i < myarray.length; i++) {// do something with myarray[i]}?? ?A problem with this pattern is that the length of the array is accessed on every loop?iteration. This can slow down your code, especially when myarray is not an array but?an HTMLCollection object. HTMLCollections are objects returned by DOM methods such as:
? document.getElementsByName()? document.getElementsByClassName()? document.getElementsByTagName()?? ?There are also a number of other HTMLCollections, which were introduced before the?DOM standard and are still in use today. There include (among others):
? document.imagesAll IMG elements on the page? document.linksAll A elements? document.formsAll forms? document.forms[0].elementsAll fields in the first form on the page???The trouble with collections is that they are live queries against the underlying??document(the HTML page). This means that every time you access any collection’s length, you’re querying the live DOM, and DOM operations are expensive in general.
for (var i = 0, len = myarray.length; i < len; i++) {// do something with myarray[i]}??This way you retrieve the value of length only once and use it during the whole loop.Note that when you explicitly intend to modify the collection in the loop (for example,by adding more DOM elements), you’d probably like the length to be updated and not constant.
console.log(typeof un); // "undefined"console.log(typeof deux); // "undefined"console.log(typeof trois); // "undefined"var jsstring = "var un = 1; console.log(un);";eval(jsstring); // logs "1"jsstring = "var deux = 2; console.log(deux);";new Function(jsstring)(); // logs "2"jsstring = "var trois = 3; console.log(trois);";(function () {eval(jsstring);}()); // logs "3"console.log(typeof un); // "number"console.log(typeof deux); // "undefined"console.log(typeof trois); // "undefined"?
(function () {var local = 1;eval("local = 3; console.log(local)"); // logs 3console.log(local); // logs 3}());(function () {var local = 1;Function("console.log(typeof local);")(); // logs undefined}());?Number Conversions with parseInt()
var month = "06",year = "09";month = parseInt(month, 10);year = parseInt(year, 10);?? ?In this example, if you omit the radix parameter like parseInt(year), the returned value will be 0, because “09” assumes octal number (as if you did parseInt(year, 8)) and 09 is not a valid digit in base 8. Alternative ways to convert a string to a number include:
+"08" // result is 8Number("08") // 8?? These are often faster than parseInt(), because parseInt(), as the name suggests, parses and doesn’t simply convert. But if you’re expecting input such as “08 hello”, parseInt() will return a number, whereas the others will fail with NaN.