JavaScript Patterns読書ノート(一)
9228 ワード
一.Global全ローカルにおけるthis=window. Another antipattern that creates implied globals to chain assignments as part of a var declaration.In the follwing snippet、a is local but b ベッカムglobal,which is probably not what you meant to do: Side Effects When Forgetting var: The’s one slight difference between implied globals and explicitly defined ones-the difference is in the ability to undefine the se variables using the delete operator: • Globals created with var(those created in the program out side of any function)cannot be deleted. • Implied globals created without var(regardless if created inside functions)can be deleted. This shows that implied globals are technically not real variables、but they are properties of the global object.Propties can be deleted with the delete operator wheres variables cannot: Hoisting:A Problem with Scatered vars JavaScript enables you to have multiple var statements anywhere in a function,and they all act as if the variables were declared the top of the function.This behavior is known as hoisting.This can lead to logical errors when you use a variable and then you declare it further in the function.For JavaScript,as long as a variable is in the same scope(same function)、it's considedeclead、even when it's used before the var declaration.Take a look at this example: for Loops In for loops you iterate over arrays or array-like objecs such as argments and HTMLCollects.The usual for loop pattern looks like the follwing: Function constructor Using the new Function()construct is simimillar to eval()and shound be proached with care.It could be a powerful construct but is oten misused.If you soutely museval()は、you conder fider nence.will be running in a local function scope、so any variables defined with var in the code being evaluated will not becomme globals atomatially. Another way to prevent atomatic globals is to wrap the eval()call into an immediate function.Consinder the follwing example.Here only un remans as a global variable polluting the namespace: Number Coversions with parseInt() Using parseInt()you can get a numeric value from a string.The function accepts a second radix parameter、which isoteted buuldn't be.The problems occur when ststriing to parsstastastastastartth with th forrerererererererererererereaaaaattttdedededededededededededededededededededererererererererererererereaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(base 8)in ECMAScript 3;however,this has changed in ES 5.To avoid inconsistency and unexpected reults,always specify the radix parameter:
myglobal = "hello"; // antipattern
console.log(myglobal); // "hello"
console.log(window.myglobal); // "hello"
console.log(window["myglobal"]); // "hello"
console.log(this.myglobal); // "hello", this = window.
// antipattern, do not use
function foo() {
var a = b = 0;
// ...
}
If you’re wondering why that happens,it’s because of the right-to-left evalution. First,the expression b=0 is evaluated and in this case b is not declared.The return value of this expression is 0,and it’s assigned to the new local variable declared with var a. In other wods,it’s as if you’ve typed: var a = (b = 0);
If you’ve already declead the variables、chaining assignments is fine and doesn’t create unexpected globals.Example:function foo() {
var a, b;
// ...
a = b = 0; // both local
}
// define three globals
var global_var = 1;
global_novar = 2; // antipattern
(function () {
global_fromfunc = 3; // antipattern
}());
// attempt to delete
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true
// test the deletion
typeof global_var; // "number"
typeof global_novar; // "undefined"
typeof global_fromfunc; // "undefined"
In ES 5 strict mode、assignments to undeclead variables(such as the two antipatterns in the preceding snippet)will throw an error.// antipattern
myname = "global"; // global variable
function 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 declead and therefore the function shoud probably「see」 the global myname.But that’s not how it works.The first alert will say“undefined” because myname is considededeclead as a local variable to the function.(Although the) declaration compes after.)All the variable declarations get hoisted to the top of the function.The refore to avoid this type of confusion,it’s best to declare ufront all variables you inted to use. The preceding code snippt will behave as if it were implemented like so:myname2 = "global"; // global variable
function func_fixed() {
var myname2; // same as -> var myname = undefined;
alert(myname2); // "undefined"
myname2 = "local";
alert(myname2); // "local"
}
func_fixed();
// sub-optimal loop
for (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 everloop iteration.This can slow down your code,especially when myarray is not an ary but an HTMLCollect.HTMLCollects returned by DOM methods such as:• document.getElementsByName()
• document.getElementsByClassName()
• document.getElementsByTagName()
The re are also a number of other HTMLCollections,which were introd before the DOM standard and are still in use today.The e include(among others):• document.images
All IMG elements on the page
• document.links
All A elements
• document.forms
All forms
• document.forms[0].elements
All fields in the first form on the page
The trouble with collection s is that they are live queries against the undering document(the HTML page).This means that everry time you access any collection's length,you’re querying the live DOM,and DOM operations are expensive in general. That’s why a better pattern for loops is to cache the length of the array (or collection)you’re iterating over,as shown in the follwing example: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 explicitly to modify the collection in the loopconsole.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"
Another difference between eval()and the Function constructor is that eval can interfere with the scope chain whers Function is much more sadbox.No mater where you execute Function,it sees only the global scope.So it can do less local variable pollution.In the follwing example,eval()can access and modify a variable in its outer scope,whers Function cannot(also note that using Function or new Function is identical):(function () {
var local = 1;
eval("local = 3; console.log(local)"); // logs 3
console.log(local); // logs 3
}());
(function () {
var local = 1;
Function("console.log(typeof local);")(); // logs undefined
}());
var month = "06",
year = "09";
month = parseInt(month, 10);
year = parseInt(year, 10);
Inbers is example,if you omit the radix parameter like parseInt,the returned value will be 0,because“09”as if you did parseInt(year,8)and Al 09 is not a valight clive.stration. The e a re offten faster than parseInt()は、because parseInt()、as the name suggas、parses and doesn't simply convert.But if you're expecting input such as'08 helle、parseInt(will therever)