zoukankan      html  css  js  c++  java
  • 理解javascript的闭包,原型,和匿名函数及IIFE

    理解javascript的闭包,原型,和匿名函数(自己总结)

    一 .>关于闭包

    理解闭包 需要的知识
    1.变量的作用域

    例1:
    var n =99; //建立函数外的全局变量
    function readA(){
        alert(n); //读取全局变量
    }
    readA(); //执行此函数
    例2:
    function readB(){
        var c = 9;
        function readC(){
            console.log(c); //ok c可见
        }
        return readC;
    }
    alert(c); //error  c is not defined.

        note:  函数内部声明变量c时,一定要加上 var,否则 c会成为一个全局变量


    所以函数内可见全局变量,函数内的局部变量却对外不可见
    js的作用域是链式的,父对象里的变量总对子对象可见,子对象的对象却对父对象不可见
    当我们要获取函数内的内部变量

    于是有了例3:

    function readB(){
       var c = 9;
       function readC(){
           console.log(c);
       }
       return readC();
    }
    readB();

    闭包很类似基于此做了一个变式

    function readB(){
        var c = 9;
        function readC(){
           console.log(c);
        }
        return readC;
    }
    var res = readB();
    res();

    note:
    1.慎用闭包,注意内存占用,因为它会保存父函数的状态
    2.不要随便改变父函数内部变量的值

    理解闭包
       note: this 指包含它的函数被执行时所属的对象

    例1:
    var name = "The Window";
    
    var object = {
        name : "My Object",
    
      getNameFunc : function(){   //此时this (这个执行函数)是属于object对象的,是object对象下的一个属性的值
          return function(){      //此时this (这个执行函数)是一个匿名函数,从根对象window生成,是属于window
            return this.name;
        };
      }
    };
    console.log(object.getNameFunc()());  //the window 
    例2:
    var name = "The Window";
    
    var object = {
        name : "My Object",
    
        getNameFunc : function(){
            var that = this;
          return function(){
              return that.name;
          };
    
        }
    };
    console.log(object.getNameFunc()());   //My Object

    二 .>匿名函数 IIFE
    直接定义一个匿名函数 然后调用这个匿名函数,这种形式在jquery插件的定义时很常见

    1.通过函数字母量的方式. 先声明一个匿名函数,然后执行它

    ( function(){
        console.log('excute self');
    }) ();

    2.通过优先表达式的方式 , 由于Javascript执行表达式是从圆括号里面到外面,所以可以用圆括号强制执行声明的函数

    (
        function () {
            alert(2);
        }
        ()
    );


    3.void操作符 用void操作符去执行一个没有用圆括号包围的一个单独操作数

    void function(){ console.log('void') } ();
    在Bootstrap源码(具体请看《Bootstrap源码解析》)和其他jQuery插件经常看到如下的写法: 
    Js代码  
    
        +function ($) {   
          
        }(window.jQuery);  
    
     这种写法称为:
    IIFE (Imdiately Invoked Function Expression 立即执行的函数表达式)
    
    一步步来分析这种代码:
    先弄清 函数表达式(function expression)和 函数声明(function declaration)的区别:
    
    函数表达式  Function Expression - var test = function() {}; 
    函数申明     Function Declaration - function test() {};
    
    函数表达式中的函数可以为匿名函数,也可以有函数名,但是该函数实际上不能直接使用,只能通过表达式左边的变量 a 来调用
    var a = function(){  
      alert('Function expression');  
    }  
    var b = new a(); 
    
    函数声明时必须有函数名
    function a(){  
      alert('Function declaration');  
    }  
    a(); 
    
    这是一个匿名函数
    function () {  
      
    }  
    你也许注意到匿名函数在console下会报错。console的执行和报错如下:
     function(){} 
    SyntaxError: Unexpected token (
    
    通过一元操作符+变成了函数表达式。
    也可以使用 - ~ !等其他一元运算符或者括号,目的是为了引导解析器,指明运算符附近是一个表达式。以下是三种经典方式 :
    +function () {   
      
    };  
      
    (function () {  
      
    });  
      
    void function() {  
      
    };  
    
    函数表达式通过 末尾的() 来调用并运行。就是一个IIFE
    +function () {   
      
    }();  
      
    (funtion () {  
      
    })();  

    参考:http://suqing.iteye.com/blog/1981591/

    三 .>关于prototype

    原型 prototype

    理解js中的protitype首先需要明白js的面向对象设计
     

    function People(name){
        this.name = name;
    
        console.log(this);  //Window 或者 object { name: 'xxx' }
        this.introduce = function(){    //实例对象方法
            console.log(this.name);
        }
    }
    
    new People('leon').introduce();
    
    //这里有一个非常有趣的现象,结合前面的来看的话,
    //首先function people里的this指向的默认是Window对象
    //当 调用 People();时 this 输出为 Window对象
    //但一旦调用new People('xx')时, this 输出为 {name:'xx'}
    //其实也很好理解,一旦new ,便新建了一个对象

    实例对象方法只能这样 new People('leon').introduce(); 调用 因为它使用前必须初始化

    类的对象的静态方法

    var People = {};  //等于一个对象 {} 或者 function 数组都可以 此时People需要是引用类型
    People.sayhi = function(to_who){
        console.log('hi '+ to_who);
    }
    
    People.sayhi('lee'); //调用时这样调用


    原型方法

    var People = function(){};             // People 必须为一个 function(){} 即为一个类,不能是对象或值类型或其他引用类型
    People.prototype.meet = function(meet_who) {
        console.log('I am '+this.name + ',going to meet ' + meet_who);
    };

    new People('lee').meet('xx');

    原型方法只能由该类的对象 调用
     A.prototype = new B(); 
    原型看起来很像继承,但其实不是,它更像clone更准确
    如果出现了父类和子类出现了重名的属性,采取就近原则,如果找不到一级一级向上找,如果要指定调用上级的属性,使用call方法

    function baseClass()
    {
      this.showMsg = function()
      {
         alert("baseClass::showMsg");   
      }
    }
    
    function extendClass()
    {
    }
    
    extendClass.prototype = new baseClass();
    var instance = new extendClass();
    instance.showMsg(); // 显示baseClass::showMsg

    extendClass.prototype = new baseClass();
    var instance = new extendClass();

    var baseinstance = new baseClass();
    baseinstance.showMsg.call(instance);

    obj1.func.call(obj);

  • 相关阅读:
    Python调用R语言
    走迷宫(用栈模拟实现非递归,并输出路径)
    走迷宫(用栈模拟实现非递归,并输出路径)
    《Python数据可视化编程实战》
    《Python数据可视化编程实战》
    一道思考题(二进制枚举的应用的想法)切金条
    Android 自己定义UI圆角button
    Oracle 用户管理(二)
    最大团解析及用处
    用反射完毕学生管理系统(包含数据库连接)
  • 原文地址:https://www.cnblogs.com/isdom/p/webclips012.html
Copyright © 2011-2022 走看看