zoukankan      html  css  js  c++  java
  • javascript闭包新认识

    Joe Zim's JavaScript Blog

     

    http://www.joezimjs.com/javascript/javascript-closures-and-the-module-pattern/

    Main menu

    Post navigation

     Previous Next

    JavaScript Closures and the Module Pattern

    JavaScript Closures and the Module PatternOne of the most widely used design patterns in JavaScript is the module pattern.  The module pattern makes use of one of the nicer features of JavaScript – closures – in order to give you some control of the privacy of your methods so that third party applications cannot access private data or overwrite it. In this post I’ll teach you what a closure is, how it works, and how to utilize it to implement the module pattern in your own JavaScript code.

    What is a Closure?

    Closures are a construct of the JavaScript language. Within JavaScript all variables are accessible from the global scope except variables that are declared within a function using the var keyword.

    1. variable1 = 1// Global Scope
    2. var variable2 = 2// Not within a function: Global Scope
    3.  
    4. function funcName() {
    5.     variable3 = 3// No var keyword: Global Scope
    6.     var variable4 = 4// Local Scope only
    7. }

    Within a function, you also have access to the global scope and every other scope above the function that you are in. In other words an inner function has access to the variables that are within the function that wraps it.

    1. var globalvar = 1// Global Scope
    2.  
    3. function outer() {
    4.     var outervar = 2// Scope is within outer()
    5.    
    6.     function inner() {
    7.         var innervar = 3// Scope is within inner()
    8.         console.log(globalvar)// => 1
    9.         console.log(outervar)// => 2
    10.         console.log(innervar)// => 3
    11.     }
    12.    
    13.     console.log(globalvar)// => 1
    14.     console.log(outervar)// => 2
    15.     console.log(innervar)// => Reference Error;
    16. }
    17.  
    18. console.log(globalvar)// => 1
    19. console.log(outervar)// => Reference Error
    20. console.log(innervar)// => Reference Error

    Every real JavaScript programmer should know this if he or she wants to become great. Knowing this, you can come to the conclusion that there is a way to keep all of your code outside of the global namespace and you would be correct. This is especially helpful when you don’t want to give anyone a chance to override any of your code without your permission. You can accomplish this by using an anonymous function (no name is given to it and it is not assigned to a variable) that immediately executes itself. This is commonly known as a Self-Invoking Anonymous Function (SIAF), though it is probably more accurately referred to as anImmediately Invoked Function Expression (IIFE – pronounced “iffy”) by Ben Alman.

    1. (function() {
    2.     // This function immediately runs and all variables within here are private
    3. }());

    Right after the closing curly brace, just put an opening and closing parenthesis and the function will immediately be executed. The parentheses around the entire function expression aren’t necessary for the code to run, but are generally used as a signal to other developers that this is an IIFE, not a standard function. Some people like to prefix with an exclamation point (!) or a semicolon (;), rather than wrapping the whole thing in parentheses.

    Using Closures for the Module Pattern

    Knowing what we know about closures, we can create objects using the module pattern.  By returning an object or variable and assigning it to a variable outside of the function, we can expose whatever we wish to the outside world, so we can have both public and private methods.

    1. var Module = (function() {
    2.     // Following function is private, but can be accessed by the public functions
    3.     function privateFunc() { … };
    4.    
    5.     // Return an object that is assigned to Module
    6.     return {
    7.         publicFunc: function() {
    8.             privateFunc()// publicFunc has direct access to privateFunc
    9.         }
    10.     };
    11. }());

    That’s essentially the module pattern right there.  You can also use the arguments to send in and shrink the name of commonly used assets:

    1. var Module = (function($, w, undefined) {
    2.     // …
    3.     // return {…};
    4. }(jQuery, window));

    I sent in jQuery and window, which were abbreviated to $ and w, respectively. Notice that I didn’t send anything in for the third argument. This way undefined will be undefined, so it works perfectly. Some people do this with undefined because for whatever reason it is editable. So if you check to see if something is undefined, but undefined has been changed, your comparison will not work. This technique ensures that it will work as expected.

    The Revealing Module Pattern

    The revealing module pattern is another way to write the module pattern that takes a bit more code, but is easier to understand and read sometimes. Instead of defining all of the private methods inside the IIFE and the public methods within the returned object, you write all methods within the IIFE and just “reveal” which ones you wish to make public within the return statement.

    1. var Module = (function() {
    2.     // All functions now have direct access to each other
    3.     var privateFunc = function() {
    4.         publicFunc1();
    5.     };
    6.    
    7.     var publicFunc1 = function() {
    8.         publicFunc2();
    9.     };
    10.    
    11.     var publicFunc2 = function() {
    12.         privateFunc();
    13.     };
    14.    
    15.     // Return the object that is assigned to Module
    16.     return {
    17.         publicFunc1: publicFunc1,
    18.         publicFunc2: publicFunc2
    19.     };
    20. }());

    There are a few advantages to the revealing module pattern versus the normal module pattern:

    1. All the functions are declared and implemented in the same place, thus creating less confusion.
    2. Private functions now have access to public functions if they need to.
    3. When a public function needs to call another public function they can callpublicFunc2() rather thanthis.publicFunc2(), which saves a few characters and saves your butt if thisends up being something different than originally intended.

    The only real downside to the revealing module pattern, as I said, is that you have to write a bit more code because you have to write the function and then write its name again in the return statement, though it could end up saving you code because you can skip the this. part.

    Module Pattern for Extension

    The last thing I wanted to talk about was using the module pattern for extending already-existing modules. This is done quite often when making plugins to libraries like jQuery, as you can see below.

    1. var jQuery = (function($) {
    2.     $.pluginFunc = function() {
    3.         …
    4.     }
    5.    
    6.     return $;    
    7. }(jQuery));

    This code is pretty flexible because you don’t even need the var jQuery = or the returnstatement near the end. jQuery will still be extended with the new method without them. It’s actually probably bad for performance to return the entire jQuery object and assign it, however, if you want to assign jQuery to a new variable name at the same time that you’re extending it, you can just change jQuery on the first line to whatever you want.

    A Foregone Conclusion

    That’s all there is for today, friend. These are common techniques and features, so even if you don’t make use of the knowledge from this post, keep it in the back of your mind just in case it comes up (which it probably will). Also, make sure to stop in again on Thursday to read about requestAnimationFrame: a new API coming out in browsers to make animations smoother and cleaner. Finally, don’t forget to share and comment below. Thanks and Happy Coding!

    Related posts:

    1. JavaScript Design Patterns: Command
    2. JavaScript Design Patterns: Observer
    3. JavaScript Design Patterns: Singleton
    4. JavaScript Design Patterns: Adapter
    5. JavaScript Design Patterns: Factory
    This entry was posted in JavaScript and tagged design patternshow tojavascriptpluginsecurity byJoseph Zimmerman. Bookmark the permalink.

    Add New Comment

    Showing 4 comments

    • infocyde

      Thanks for sharing this, I think I have a better grasp of closures now.

       
       
    •  You think you do? Well, if you have any questions, feel free to contact me via the form on this site or FB/Twitter/G+. Any of those will work. You can find links to my social profiles in the footer (or at the top of the sidebar if you happen to be on a page that shows the sidebar.

       
       
    • Robin

      Your second code example is either confusing or incorrect:

      console.log(outer) does not produce undefined, it will log the outer function itself.
      console.log(innter) does not produce undefined, it will cause a ReferenceError which if uncaught is fatal.

      There is a big difference between a variable being undefined and a variable not existing at all.

      For example:
      var iExist;
      console.log(iExist) => undefined

      console.log(iDontExist) => ReferenceError

       
       
    • You're quite correct. Sorry about the confusion. 1st off I wasn't thinking, so I named the variables the same as the functions that they were within, so I now changed them to have a "var" suffix. Also I went back and changed the comments from saying "undefined" to ReferenceError. Thanks for catching that.

       
       
     

    MEET THE AUTHOR

    I started web development in 8th grade and I've been stuck with the sickness ever since. Now I'm attempting to infect the world with the same sickness via this blog. Read more About Me.

        

    NEWSLETTER SIGNUP

     

  • 相关阅读:
    Spring Boot -- Spring Boot之@Async异步调用、Mybatis、事务管理等
    Spring Boot -- 认识Spring Boot
    大数据 -- Cloudera Manager(简称CM)+CDH构建大数据平台
    大数据 -- kafka学习笔记:知识点整理(部分转载)
    大数据 -- Hadoop集群环境搭建
    大数据 -- zookeeper和kafka集群环境搭建
    Java基础 -- 数组
    sbt spark2.3.1 idea打包Caused by: java.lang.ClassNotFoundException: scala.Product$class
    windows 安装python pip Could not install packages due to anEnvironmentError: [WinError 5] 拒绝访问
    博客园编辑数学公式的方法
  • 原文地址:https://www.cnblogs.com/MyFlora/p/2482621.html
Copyright © 2011-2022 走看看