Note On <You Don't Know JS - Scope and Closures>
2014-07-30 10:16
561 查看
Chapter 2: Lexical Scope
Some highlights:
All the optimizations Javascript engine would make are invalid if eval() or with are present, so the engine just simply does NOT perform any optimization at all. That's why the two utilities are frowned up in the community as
bad practices.
setTimeout(), setInterval() and new Function() are also said to be bad practices,but what is the alternative to setTimeout()?
Chapter 3: Functions Versus Block Scope
Some highlights:
By using function expression, you can limit the function name identifier to reside only in that function's own scope.
var a = 2; (function foo(){ // <-- insert this var a = 3; console.log( a ); // 3 })(); // <-- and this console.log( a ); // 2
Function Expression VS. Function Declaration
IIFE (immediately-invoked function expression)
var a = 2; (function foo(){ // <-- insert this var a = 3; console.log( a ); // 3 }()); // <-- and this console.log( a ); // 2
var a = 2; (function IIFE( global ){ var a = 3; console.log( a ); // 3 console.log( global.a ); // 2 })( window ); console.log( a ); // 2
var a = 2; (function IIFE( def ){ def( window ); })(function def( global ){ var a = 3; console.log( a ); // 3 console.log( global.a ); // 2 });
It is always better to provide a name in function expression, therefore the author would NOT recommend anonymous callback function;
'catch' keyword creates a block scope;
use 'let' keyword to create block scope, which is relevant to closures and garbage collection;
var foo = true; if (foo) { let bar = foo * 2; console.log( bar ); } console.log( bar ); // ReferenceError
var foo = true; if (foo) { { // <-- explicit block let bar = foo * 2; console.log( bar ); } } console.log( bar ); // ReferenceError
{ console.log( bar ); // ReferenceError! let bar = 2; }
let keyword is not supported by Chrome, or IE 10.
'const' is supposed to create block-level variable
var foo = true; if (foo) { var a = 2; const b = 3; // block-scoped to the containing `if` a = 3; // just fine! b = 4; // error! } console.log( a ); // 3 console.log( b ); // ReferenceError! , nothing in Firefox
It is different in practice than what is said in this book, in both Chrome and Firefox, 'const' makes the variable accessible from the out-containing scope, instead of making it a local block variable.
And in IE, it even throws an error:
Chapter 4: Hoisting
a = 2; var a; console.log( a ); // 2 //////////////////////// console.log( b_V ); // undefined var b_V = 2;
Some highlights:
If the statement is like: var boo = function(){}, then it will be interpreted as two separate parts: declaration & assignment, and only the declaration will be hoisted.
/* only declaration is hoisted, but function expression */ foo_V_1(); // not ReferenceError, but TypeError! var foo_V_1 = function bar() { // ... };
/* name identifier in function expression is not hoisted */ foo_V_2(); // TypeError bar_V_2(); // ReferenceError var foo_V_2 = function bar_V_2() { // ... };
Otherwise, if the statement is a function expression like: function boo(){}, it will be hoisted as a whole.
foo_V_0(); function foo_V_0() { var c_V = 2; console.log( c_V ); }
If the same name identifier is assigned to with a variable and appears in a function expression as well, then the one for function will be hoisted, and the statements assigning other values to the identifier as variable will
be ignored.
/*Function First*/ foo_V_3(); // 1 var foo_V_3; // should be hoisted, but it is variable, so it is omitted function foo_V_3() { // should be hoisted, and it is function, so it is hoisted firstly console.log( 1 ); } foo_V_3 = function() { // will override the previous definition console.log( 2 ); };
However, if there is other statements assigning function expressions to the identifier follows, then function definition will be overridden.
foo(); // 3 function foo() { console.log( 1 ); } var foo = function() { console.log( 2 ); }; function foo() { console.log( 3 ); }
Function declaration will be hoisted to the enclosing scope, that may across the block, but the sample code fails to run in Firefox.
foo_V_5(); // "b" var a_V_5 = true; if (a_V_5) { function foo_V_5() { console.log("a"); } } else { function foo_V_5() { console.log("b"); } } //Throw ReferenceError: foo_V_5 is not defined in Firefox
Chapter 5: Scope Closure
Some highlights:
The function is being invoked well outside of its author-time lexical scope. Closure lets the function continue to access the lexical scope it was defined in at author time.
function foo() { var a = 2; function baz() { console.log( a ); // 2 } bar( baz ); } function bar(fn) { fn(); }
var fn; function foo() { var a = 2; function baz() { console.log( a ); } fn = baz; // assign baz to global variable } function bar() { fn(); } foo(); bar(); // 2
Module pattern
function CoolModule() { var something = "cool"; var another = [1, 2, 3]; function doSomething() { console.log( something ); } function doAnother() { console.log( another.join( " ! " ) ); } return { doSomething: doSomething, doAnother: doAnother }; } var foo = CoolModule(); foo.doSomething(); // cool foo.doAnother(); // 1 ! 2 ! 3To state it more simply, there are two requirements for the module pattern to be exercised:
There must be an outer enclosing function, and it must be invoked at least once (each time creates a new module instance).
The enclosing function must return back at least one inner function, so that this inner function has closure over the private scope, and can access and/or modify that private state.
Module as singleton.
var foo = (function CoolModule() { var something = "cool"; var another = [1, 2, 3]; function doSomething() { console.log( something ); } function doAnother() { console.log( another.join( " ! " ) ); } return { doSomething: doSomething, doAnother: doAnother }; })(); foo.doSomething(); // cool foo.doAnother(); // 1 ! 2 ! 3
Passing parameter when creating module.
function CoolModule(id) { function identify() { console.log( id ); } return { identify: identify }; } var foo1 = CoolModule( "foo 1" ); var foo2 = CoolModule( "foo 2" ); foo1.identify(); // "foo 1" foo2.identify(); // "foo 2"
Singlton design with parameters.
var foo = (function CoolModule(id) { function change() { // modifying the public API publicAPI.identify = identify2; } function identify1() { console.log( id ); } function identify2() { console.log( id.toUpperCase() ); } var publicAPI = { change: change, identify: identify1 }; return publicAPI; })( "foo module" ); foo.identify(); // foo module foo.change(); foo.identify(); // FOO MODULE
APPENDIX
Some highlights:
Javascript does NOT support dynamic scope, which means to care about where the functions are called from rather than how and where they are declared
function foo() { console.log( a ); // 2 } function bar() { var a = 3; foo(); } var a = 2; bar();
You may be confused and mix closure up with dynamic scope, try the following snippets may help to clear it up:
function foo() { console.log( a ); // ReferenceError: a is not defined } function bar() { var a = 3; foo(); } bar();
function bar() { var a = 3; function foo() { console.log( a ); // 3 } foo(); } var a = 2; bar();
function bar() { var a = 3; function foo() { console.log( a ); // 3 } foo(); } bar();
The trick to use block scope in pre-ES6 environments
try {throw 2} catch(a){ console.log( a ); // 2 } console.log( a ); // ReferenceError, but in Chrome & Firefox I got 2,
相关文章推荐
- Note On <You Don't Know JS - this and Object Prototypes>
- Note on <Zend Framework - A Beginner's Guide> - 02 ZF原理;继续解决第二章的问题
- Note On <Pro AngularJS> - 01
- Note on <Zend Framework - A Beginner's Guide> - 07
- Note on <Zend Framework - A Beginner's Guide> - 04 使用Doctrine初体验
- Note on <AngularJS> - Aborted Because Of Too Many Errors In This Book
- Note on <Zend Framework - A Beginner's Guide> - 06
- 《You Don't Know JS》
- Note on <Zend Framework - A Beginner's Guide> - 01:Apache的URL重寫,ZF項目結構
- Note on <Professional SQL Server 2012 Internals And Troubleshooting> - 01
- Note on <Zend Framework - A Beginner's Guide> - 05
- Note on <Zend Framework - A Beginner's Guide> - 03
- you don't know js -- Scope and Closures学习笔记——第五章(闭包) 下篇
- Note On <Programming Entity Framework 2nd Edition> -02: How to Use SqlExpress Profiler 2.0
- you don't have permission to access / on this server(Apache Server权限访问问题)
- you don't know js -- Scope and Closures学习笔记——第四章(声明提升 Hoisting)
- <<醒了自悟>>系列-bozo---虫不知---Don't know what you don't know
- Note On <Programming Entity Framework 2nd Edition> -04
- you don't know js -- Scope and Closures学习笔记——第一章(什么是作用域)
- you don't know js -- Scope and Closures学习笔记——第二章(词法作用域)