好久之前转发过一篇关于Ext Store.each方法的文章。http://wangyuelucky.blog.51cto.com/1011508/1064777 只是把API给弄了过来,还有一个小例子。这就是我当时对于ext或者js的理解。


今天,刚好又用到Store.each方法,再来写两句自己的东东。


其实each的真正定义是在 Ext.util.MixedCollection中,源码如下:

each : function(fn, scope){
        var items = [].concat(this.items); // each safe for removal
        for(var i = 0, len = items.length; i < len; i++){
            if(fn.call(scope || items[i], items[i], i, len) === false){
                break;
            }
        }
    },


仿照源码,写一个纯JS的each小例子:

// 类定义
var Store = function(){
    this.items = [{id: 1},{id: 2},{id :3}]; // 注意这里不能是简单值
};
// 原型方法
Store.prototype.each = function(fn){
    var items = this.items;
    for(var i = 0, len = items.length; i < len; i++){
        if(fn.call(items[i], items[i], i, len) === false){ // 关键
            break;
        }
    }
};
                                                                                                                                                                                                 
// 实例化对象
var _store = new Store(); // 调用prototype方法,需要实例化对象
_store.each(function(item){
    console.log(item.id); // 1 2 3
});
//..


今天的重点不是each方法怎样写,而是fn的变量作用域问题。将上述代码简单修改,如下:

var Store = function(){
    this.items = [{id: 1},{id: 2},{id :3}];
};
Store.prototype.each = function(fn){
    var items = this.items;
    for(var i = 0, len = items.length; i < len; i++){
        if(fn.call(items[i], items[i], i, len) === false){
            break;
        }
    }
};
       
var _store = new Store(),
    index = 0; // 注意
       
_store.each(function(item){
    console.log(item.id); // 1 2 3
    console.log(index); // 0 1 2
    index++;
});
console.log(index); //3


以前的时候,老犯糊涂,认为Store.prototype.each不能访问当前作用域的index。而且跟闭包弄混了,一看到(function{}) 就觉得是闭包。


其实,上面的方法就是普通的函数调用,没有闭包。只是写法上有点唬人。把fn提出来,就清楚多了,如下:

var Store = function(){
    this.items = [{id: 1},{id: 2},{id :3}];
};
Store.prototype.each = function(fn){
    var items = this.items;
    for(var i = 0, len = items.length; i < len; i++){
        if(fn.call(items[i], items[i], i, len) === false){
            break;
        }
    }
};
    
var _store = new Store(),
    index = 0;
    
var myFn = function(item){
    console.log(item.id); // 1 2 3
    console.log(index); // 0 1 2
    index++;
};
_store.each(myFn); // 把fn放到外面
console.log(index);// 3


each方法会三次调用myFn方法:

每一次的时候,myFn会在当前作用域找index,找不到则到上一层作用域找,找到后修改index的值。如此而已。解剖之后如下:

var Store = function(){
    this.items = [{id: 1},{id: 2},{id :3}];
};
var _store = new Store(),
    index = 0;
var myFn = function(item){
    console.log(item.id); // 1 2 3
    console.log(index); // 0 1 2
    index++;
};
myFn(_store.items[0]);
myFn(_store.items[1]);
myFn(_store.items[2]);
console.log(index); // 3


很清楚了,不是。