理解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);

posted @ 2015-10-17 17:16  wifix  阅读(1375)  评论(0编辑  收藏  举报