改变函数执行的上下文

参考阅读: js教程:javascript作用域(Scope)

JavaScript中 this代表的是运行时的对象,是正在调用代码的对象

在浏览器环境中运行需要把println函数改成alert或者console.log

function gf() {println(this)}


运行这段代码输出:[object global]

下面这段代码人为改变了代码执行的上下文,this也就代表着不同的对象
var obj1 = {count:1};
var obj2 = {count:6};

function foo(factor) {this.count * factor}

foo.call(obj1, 8); //1*8
foo.call(obj2, 8); //6*8


再看
Prototype的bind方法代码
Function.prototype.bind = function() {
    var __method = this, args = $A(arguments), object = args.shift(); //Important
    return function() {
        return __method.apply(object, args.concat($A(arguments)));
    }
}

// 上面这种方法没怎么明白,把arguments转换成Array,然后把执行函数绑定在第一个方法的参数上(把绑定的对象提取出来)
// 绑定参数又增加args.concat($A(arguments)),这多出来的几行代码是什么意图?
// 原来这样是为了
// 在bind函数执行的时候可以添加一次参数
// 然后在后期bind返回的函数执行的时候又可以添加一次参数
// 这样在函数执行的上下文变化时还能“记忆”之前的参数,这就是JS的必包特性
// http://mengjiaoyao.blog.163.com/blog/static/298416192009113102149773/


// 将传入的对象转化成Array
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0, length = iterable.length; i < length; i++)
      results.push(iterable[i]);
    return results;
  }
}


早期的Prototype中bind方法更简单明了
Function.prototype.bind = function(object) {
    var method = this; //Important
    return function() {
        method.apply(object, arguments);
    }
}


改写我们上面代码
var foo1 = foo.bind(obj1);
foo1(8);


两次传参的调用代码
var obj1 = {count:1};
var obj2 = {count:6};

function foo(a,b,c) {println(this.count * a * b * c)}


var foo1 = foo.bind(obj1, 2);
var foo2 = foo.bind(obj2, 3);
foo1(5,6);
js>60 // 1 * 2 * 5 * 6
foo2(7,8);
js>1008 // 6 * 3 * 7 * 8


这就是改变函数执行上下文+记忆不同上下文之间参数的结果


如果不想用prototype这种方式的写法的话,可以参考如下代码
var gbind = function(o, f) {
    return function() {
        return f.apply(o, arguments);
    }
};

这种写法如果需要支持更复杂的参数传递的话,想想该怎么写?

虽然看不懂,但每次想这个问题还得看一遍
引用
A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).


以下纯淡腾乱作,请蒙上眼睛
//another version xscript%#%live.com
//实在没有必要这么写
//bindAsEventListener()返回的函数必须至少带一个参数,那就是event,否则在FF无法运行
Function.prototype.bindAsEventListener = function() {
    var __method = this, args = $A(arguments), object = args.shift();
    return function() {
        var a = $A(arguments), e, evts;
        var __e_m = "警告,您的浏览器必须指定第一个参数类型为事件!";
        // 如果后期传入了参数
        // alert(a.length); // IE和W3C输出的不一样,应该好好学学,理解
        if(0 < a.length) {
            e = a[0];
            //alert(typeof e);
            //alert(e.type);
            // 如果是事件,判断对象是否事件还有待改进
            // 
            if("object" == typeof e && !!e.type && !!e.srcElement) {
                a.shift();
                evts = [e || window.event];
            } else if(!window.event) { // 而且window.event都无法捕捉到
                true == !!console.log ? console.log(__e_m) : alert(__e_m);
                return false;
            } else {
	            evts = [window.event];
            }
        } else {
            if(!!window.event) {
                evts = [window.event]; 
            } else {
                true == !!console.log ? console.log(__e_m) : alert(__e_m);
                return false;
            }
        }
        return __method.apply(object, evts.concat(args).concat(a));
    }
}

你可能感兴趣的:(JavaScript,浏览器,prototype,IE,Blog)