What design patterns take advantage of JavaScript manipulation?

An excellent article by Ben Cherry explains the rise in JavaScript . My problem, however, is that I cannot imagine a precedent for this notorious messenger. Please explain if there is a design template that really takes advantage of this language feature.

Secondly, is the scope unique to JavaScript?

UPDATE --- I am adding generosity to an answer that satisfies my curiosity: Which design patterns do use JavaScript-hoisting behavior? I understand why JavaScript supports lifting, but I want to know how I can use this feature.

+43
javascript scope hoisting
Dec 21 '11 at 10:56 a.m.
source share
9 answers

Variable lift

One of the easiest lifting applications is moving a variable. If we did not have a raise variable, this would throw a ReferenceError :

 var bar = foo; var foo; 

This does not seem immediately useful, but it allows us to do such things:

 var myCoolJS = myCoolJS || {}; 

This basically means that it looks like this: myCoolJS is myCoolJS if it exists, or a new object if it does not. The second myCoolJS does not throw a ReferenceError if myCoolJS does not exist yet because this variable declaration is raised.

This saves us from having to do an inconvenient check of typeof myCoolJS != 'undefined' .

Lift function

The lift function can be especially useful when combining several scenarios into one. For example, I created an easy implementation of the assembly time of CommonJS modules . This provides the same module , require and exports functions that are in node.js. I built the tool so that the necessary modules consist of several files. For example, require('/foo') can lead to the creation of a module consisting of two files, foo.js ("body file") and foo.h.js ("header file").

This allows the "body file" not to know about the free variables provided by the CommonJS module environment; all this is processed in the header. This makes the code reusable and easily tested without assembly. However, since headers are added to the body, we use the hoisting function in the body file to allow export in headers. For example:

 // dom.h.js var util = require('util').util; exports.css = css; // we can do this because "css" is hoisted from below // ... other exports ... 

...

 // dom.js function css(){}; // this would normally just be an object. css.hasClass = function(element) { ... }; css.addClass = function(element) { ... }; // ...other code... 
+19
Mar 05 2018-12-12T00:
source share
β€” -

Used here for lifting:

 (function() { var factorial = function(n) { if(n == 0) return 1; return n * factorial(n - 1); }; })(); 

Without lifting, this will not compile, because factorial does not yet exist inside the functional literal. You will have to declare the variable separately or use a named function.

JavaScript also allows you to use the following code:

 var test = function(b) { if(b) { var value = 2; } else { var value = 5; } console.log(value); }; 

With a block scan, you must add another line to declare value before if .

To be fair, this code works because of the function's ability, not for lifting. And JavaScript could have a scope without going up. Ruby does this better: Ruby has a method scope for variables, but variables don't exist until you set them:

 def test(b) # unlike JavaScript, value is not accessible here if b value = 2 else value = 5 end puts value end 
+14
Mar 03 2018-12-12T00:
source share

JavaScript does not have a block scope (let’s forget about let ), and so the declaration of any variable is declared for the entire function from which JavaScript has a scope.

If you think about it, a JavaScript raise may make more sense.

If you remember the rise, this should not be a source of error and confusion. This is just one of those quirks that you must understand and remember.

I'm not sure if listing is limited to JavaScript. I have never heard of this elsewhere, but that does not necessarily mean that it does not exist in other languages.

+11
Dec 21 2018-11-21T00:
source share

The first two examples in this article are simply poorly written. Bad code clearly leads to errors and confusion. Let me give you refactoring versions of these examples. You will see that there is no confusion ...

Example 1 - Source Code

 var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); 

Example 1 - Refactored code (remote confusion)

 var foo = 1; function bar() { var foo; if ( !foo ) { foo = 10; } alert( foo ); } bar(); 

The warning displays "10", and it is clear why. There is no confusion.

Example 2 - Source Code

 var a = 1; function b() { a = 10; return; function a() {} } b(); alert(a); 

Example 2 - Refactored code (remote confusion)

 var a = 1; function b() { var a = function () {}; a = 10; return; } b(); alert( a ); 

The warning displays "1". Obviously. There is no confusion.

+9
Dec 21 '11 at 23:32
source share

"hoisting" is not part of the ECMAScript standard, but it says that a variable inside a function is declared at the beginning of the function, regardless of where in the function it is placed in the code.

Example

 (function() { alert(myvar); // undefined var myvar = 'local value'; })(); 

Internally, Javascript will declare myvar before the warning, show a warning, then it will assign myvar to "local value".

So, Javascript will interpret this code as:

 (function() { var myvar; alert(myvar); // undefined myvar = 'local value'; })(); 

That's why "Java the Good parts" has a guide that says you should declare a variable at the top of your function.

Source: http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/

"Please explain if there is a design template that really uses this feature of the language." "lifting" is not a function, but a consequence of how the Javascript interpreter structures the code because the language uses a function overview.

"What design patterns do JavaScript use to lift?" Answer: No.

+6
Mar 06 '12 at 15:35
source share

I think that one area where lifting is useful is related to the fact that functions are considered as objects of the first class. For example:

 function foo() { function a() { //... } function b() { //... } } 

can also be written as:

 function foo() { var a = function () { //... } var b = function () { //... } } 

Without lifting, the following will result in an error:

 function foo() { var a = function () { b(); } a(); //Error in function since b is not yet defined var b = function () { //... } } 

I believe that they can only have objects with a lens, but I believe that this would be contrary to the philosophy that functions should be considered as first-class citizens in this language.

+5
Dec 21 '11 at 23:19
source share

Here's a real use case (albeit reduced to pseudo code) for you, from someone who really would like to take advantage of the wilderness climb.

I recently wrote this script to handle simple form validation and submission. As far as possible, each function declaration calls the following. This has 2 main advantages for readability:

  • Logical sequence : the code has a sequential stream, which means that functions will always be called before they are declared. This advantage is that when used with functions with a low degree of complexity, it keeps the relationship relatively flat and gives you an idea of ​​the calling context of the function shortly before its source. You just have to scroll down (never up) to follow the code, and - as far as possible - not really or very little to scroll.
  • Low reference overhead . I like to keep all variable declarations at the top of each area so that readers know about all the moving parts that a function needs before reading through their body, but no one wants to read every function source code that is initiated to get an idea of ​​what the current area is doing actions. Using this method, you will never come across a function reference before declaring it. It sounds silly at first, but actually it reduces cognitive overhead: you are never given a function source with an implicit remember this - we will use it later - instead, you only ever read the function source as soon as you know the context that it called in.
 $( function emailHandler(){ var $form = … var $email = … var $feedback = … var value = … var validation = … // All initialisation is right here. Executes immediately. // Therefore, all future code will only ever be invoked // by call stacks passing through here. void function bindEvents(){ $email.on( 'input', filterInput ); $form.on( 'submit', preSubmit ); }(); function filterInput( inputEvent ){ if( inputEvent && inputEvent.which === '13' ){ return presubmit( inputEvent ); } return validate(); } function validate(){ var presentValue = $email.val(); if( validation.done || presentValue === value ){ return; } else if( presentValue === placeholder || presentValue === '' ){ validation.message = 'You must enter an email address to sign up'; validation.valid = false; } else if( !validation.pattern.test( presentValue ) ){ validation.message = 'Please enter a valid email address'; validation.valid = false; } else { validation.message = ''; validation.valid = true; } validation.ever = true; clearFeedback(); } function preSubmit( inputEvent ){ if( inputEvent instanceof $.Event ){ inputEvent.preventDefault(); } if( !validation.ever ){ validate(); } if( validation.pending || validation.done ){ return; } else if( validation.valid ){ return submit(); } else { return feedback(); } } function submit(){ $form.addClass( 'pending' ); // Create an XHR base on form attributes $.ajax( { cache : false, url : $form.attr( 'action' ), data : $form.serialize(), type : $form.attr( 'method' ).toUpperCase() } ) .done( success ) .fail( failure ) .always( feedback ); } function success( response ){ validation.message = response.message; validation.valid = response.valid; } function failure(){ validation.message = 'Our server couldn\'t sign you up. Please try again later.'; validation.error = true; } function feedback(){ clearFeedback(); if( validation.message ){ $feedback .html( validation.message ) .appendTo( $placeholder ); } if( !validation.valid || validation.error ){ $form.addClass( 'invalid' ); $email.trigger( 'focus' ); } else { $form.addClass( 'done' ); validation.done = true; } validation.pending = false; } function clearFeedback(){ $form.removeClass( 'invalid pending done' ); } } ); 
+4
Jan 28 '14 at 13:35
source share

I like the style of the question based on curiosity about the language. Obviously, no one should use lifting as a function, unless they are sure that their home address cannot be discovered by those who can use it later.

I can only imagine a few trivial cases. The main property to use is that a variable can be declared (but undefined) and then assigned in only one line of code, but with events interpreted at two different points.

With a declaration at the end of the loop (and not .forEach, as this of course sets the scope), you can use this to detect the first iteration.

 var notfirst = true; // this is actually never referenced. (function () { var number, stack = [1, 2, 3, 4, 5]; while (number = stack.pop()) { if (notfirst) console.log(number); var notfirst = true; } })(); 

The exit from emptying the stack is 4, 3, 2, 1. 5 is rejected.

Yet again. Do not do this!

+1
Mar 07 '12 at 1:01
source share

If you are considering how to write other languages ​​(C ++ / Java) and how their class templates can be used, you can use a similar template to create prototypes for lifting.

0
May 2 '16 at 18:08
source share



All Articles