老外写的js闭包

 

原文:https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures

老外写的很详细,有兴趣的可以看原文。(不得不佩服老外的逻辑思维能力)

下面是老外说的一个稍微有趣的例子: 

//在这个例子中,定义了一个函数makeAdder(x),它接收一个参数x和返回一个新函数。

//返回新函数接受单个参数y,并返回x和y的总和。



//在本质上,是一个函数makeAdder工厂



//add5和add10都闭包。他们共享相同的函数体定义,但存储在不同的环境。在add5环境,x是5。至于add10而言,x是10。

function makeAdder(x) {

    return function (y) {

        return x + y;

    };

}

var add5 = makeAdder(5);

var add10 = makeAdder(10);

add5.toString(); //function (y) {  return x + y; };  makeAdder内部方法

alert(add5(2)); // 7

alert(add10(2)); // 12

 接着老外又给了一个稍微实用的的例子: 

function makeSizer(size) {

    return function () {

        document.body.style.fontSize = size + 'px';

    };

}



var size12 = makeSizer(12);

size12.toString(); //function () { document.body.style.fontSize = size + 'px'; }

var size14 = makeSizer(14);

var size16 = makeSizer(16);

 

 
   
document.getElementById('size-12').onclick = size12;

document.getElementById('size-14').onclick = size14;

document.getElementById('size-16').onclick = size16;


<
a href="#" id="size-12">12</a> <a href="#" id="size-14">14</a> <a href="#" id="size-16">16</a>

 

老外开始慢慢引入重点了,还是看代码:

//闭包的模块模式 

//创建一个单一的环境,共享三功能:增量计数器。减量计数器。计数器值。

//这三个公共函数闭包,共享相同的环境。

//由于JavaScript的词法作用域,他们各自都能访问内部私有changeBy函数 privateCounter变量。

var Counter = (function () {

    var privateCounter = 0;    //私有变量

    function changeBy(val) {   //私有函数

        privateCounter += val;

    }

    return {

        increment: function () {   //返回方法

            changeBy(1);           //调用内部私有函数

        },

        decrement: function () {    

            changeBy(-1);

        },

        value: function () {       

            return privateCounter;

        }

    }

})();



 

alert(Counter.value()); /* Alerts 0 */

Counter.increment();

Counter.increment();

alert(Counter.value()); /* Alerts 2 */

Counter.decrement();

alert(Counter.value()); /* Alerts 1 */

 

怎么样,老外讲的例子还容易懂吧。

上面单一环境中,三个公共函数还是用的同一个变量。接着看:

var makeCounter = function () {

    var privateCounter = 0;

    function changeBy(val) {

        privateCounter += val;

    }

    return {

        increment: function () {

            changeBy(1);

        },

        decrement: function () {

            changeBy(-1);

        },

        value: function () {

            return privateCounter;

        }

    }

};



var Counter1 = makeCounter();

var Counter2 = makeCounter();

alert(Counter1.value()); /* Alerts 0 */

Counter1.increment();

Counter1.increment();

alert(Counter1.value()); /* Alerts 2 */

Counter1.decrement();

alert(Counter1.value()); /* Alerts 1 */

alert(Counter2.value()); /* Alerts 0 */

相信你已经看到   Counter1 Counter2 闭包变量包含一个不同的实例privateCounter。(即:两个实例的变量独立变化,互不影响)

老外又举了一个例子:创建闭包循环,一个常见的错误,看代码:
<p id="help">Helpful notes will appear here</p>

<p>E-mail: <input type="text" id="email" name="email"></p>

<p>Name: <input type="text" id="name" name="name"></p>

<p>Age: <input type="text" id="age" name="age"></p>
function showHelp(help) {

  document.getElementById('help').innerHTML = help;

}

 

function setupHelp() {

  var helpText = [

      {'id': 'email', 'help': 'Your e-mail address'},

      {'id': 'name', 'help': 'Your full name'},

      {'id': 'age', 'help': 'Your age (you must be over 16)'}

    ];

 

  for (var i = 0; i < helpText.length; i++) {

    var item = helpText[i];

    document.getElementById(item.id).onfocus = function() {

      showHelp(item.help);

    }

  }

}

 

setupHelp(); 

 

上面是错误的写法(所有的事件都提示年龄),正确的如下:

function showHelp(help) {

  document.getElementById('help').innerHTML = help;

}

 

function makeHelpCallback(help) {

  return function() {

    showHelp(help);

  };

}

 

function setupHelp() {

  var helpText = [

      {'id': 'email', 'help': 'Your e-mail address'},

      {'id': 'name', 'help': 'Your full name'},

      {'id': 'age', 'help': 'Your age (you must be over 16)'}

    ];

 

  for (var i = 0; i < helpText.length; i++) {

    var item = helpText[i];

    document.getElementById(item.id).onfocus = makeHelpCallback(item.help);

  }

}

 

setupHelp(); 
这是预期的。而不是回调都共享一个单一的环境,makeHelpCallback函数为每个调用它的对象创建一个新的环境, 。

写到这老外还没结束。

 

老外引出了:构造函数和原型 。
 
老外说:当闭包不是必要的时候,创建一个新对象/类、方法通常应该是关联到对象的原型,而不是定义成对象的构造函数。
          原因是,每当在调用构造函数的方法将得到重新分配(即为每一个对象创建)。
老外说的很明白,接下来看js 原型的写法(prototype)。
当然老外还是有例子的(看代码):
//构造函数写法

function MyObject(name, message) {

  this.name = name.toString();      //变量

  this.message = message.toString();

  this.getName = function() {       //方法

    return this.name;

  };

 

  this.getMessage = function() {

    return this.message;

  };

}

原型写法:

//原型的写法1

function MyObject(name, message) {

  this.name = name.toString();        //变量

  this.message = message.toString();  

}

MyObject.prototype = {

  getName: function() {      //方法

    return this.name;

  },

  getMessage: function() {

    return this.message;

  }

};

 

//原型的写法2

function MyObject(name, message) {

  this.name = name.toString();

  this.message = message.toString();

}

MyObject.prototype.getName = function() {

  return this.name;

};

MyObject.prototype.getMessage = function() {

  return this.message;

};

调用方法:

var a = new MyObject('zhangsan', '我是张三');

a.getMessage();

a.getName();

 

怎么样看到这里你是不是明白了:js构造函数,js 的原型(prototype),以及js闭包了。

         你是不是应该明白了js创建类,方法,属性了。 是不是有了面向对象的感觉。 

 

怎么样,老外还可以吧。。。

说说我的理由:老外写的文章,例子多,浅显易懂,循序渐进,由浅及深,逻辑缜密。

                   通篇没有什么定义(不像国人写的东西,一开始就解释名词)。

 

好吧,最后欢迎您的拍砖!

 
 

 

 

 

          

              

你可能感兴趣的:(js闭包)