this

    我给自己总结一下,this。“this“是一种动态灵活的机制。它在函数调用时确定,与调用方式有关,而非词法作用域。我这里使用DC的说法对应的另一种说法。即函数的this绑定分为隐式绑定、显式绑定、默认绑定、new绑定。下分别说明:

1、默认绑定。就是不加任何修饰的使用函数。

var  foo = function () {
       console.log(this.a); //global
}; 

var a = "global value";

 this在非严格模式下绑定在window上,严格模式下绑定于undefined。当然这要在函数体中使用"use strict";才管用。

2、隐式绑定。这种方式是在函数作为对象方法的时候this变为这个对象。

var  foo = function () {
       console.log(this.a); //global
}; 
var a = "global value";

var obj = {
a: "object",
foo: foo
};

obj.foo(); //"object"

//绑定丢失

var bar = obj.foo;
bar(); //"global value";

//函数传递参数也是按值传递的,从而也会丢失绑定
setTimeout(obj.foo, 1000) //"global value";

  但是会出现绑定丢失的情况,因为安置传递后变为了默认绑定的形式。

3、显式绑定。我直接指定函数调用的this值,当然直接使用apply、call没有问题,若使用bind方法后还是可以被new绑定改变this值。

var  foo = function () {
       console.log(this.a); //global
}; 
var a = "global value";

var obj = {
    a: "object",
    foo: foo
};
foo.apply(obj) //"object"

//丢失的例子
foo = function (v) {
this.value = v;
};
var boo = foo.bind(obj);
var bar = new boo("text");
bar.value === "text" //true
obj.value === undefined //true

//加上包装函数使得不可变

var hardbind = function () { //无论如何调用外层函数均不会改变
foo.apply(obj);
};

   那么如何不让它改变,采用所谓的硬绑定来定。即外加一个包装函数。

    一些api可直接指定函数调用的this。

[1 , 2, 3, 23].forEach(function (a) {
      console.log(a, this.info)}, {info: "outter"});
//结果
1 "outter"
2 "outter"
3 "outter"
23 "outter"

4、new绑定。略过。

 

几个有趣的问题:

     有时我们想借用某个方法,但又不在乎this值那可以使用null、undefined作为参数,但实际上却被绑定在全局对象上,这是始料未及的。见例子。

function foo (a) {
      this.a = a;
}
foo.apply(null, "where");  //这时的window.a为"where".  

    那我不想改变任何有用的对象怎么办呢?见例子:

var π = Object.create(null);

   我将this定于这里之后,不会对其他任何对象有影响。

   我想要一种绑定方式:在默认下不会绑定在undefined或是window,同时又可以在其它绑定下修改this值。

(!Function.prototype.softbind) {
      Function.prototype.softbind = function (obj) {
            var fn = this;
            var curried =Array.prototype.slice.call(arguments, 1);
            var bound = function () {
                   return fn.apply((!this || this === window) ? obj : this, 
                   curried.concat.apply(curried, arguments));      //关键步骤
            };
            bound.prototype = fn.prototype; 
            return bound; 
      };
}

var obj1 = {name: "obj1"};
var obj2 = {name: "obj2"};
var foo = function () { console.log(this.name); };
var ins = foo.softbind(obj1);
ins(); //"obj1";
obj1.foo = ins;
obj1.foo(); //"obj1";
obj2.foo = obj1.foo;
obj2.foo(); //"obj2", 因为外层函数执行的this是obj2,这时函数执行时的this不变,为obj2。

setTimeout(obj2.foo, 1000); //"obj1",原因是:obj2.foo传入后变为了默认绑定,bound函数执行的this原本应是window(这里没有使用严格模式),关键步骤中将对应的this替换为预先
//的obj1。

 

          

 

posted @ 2016-10-24 16:57  月下夜行  阅读(208)  评论(0编辑  收藏  举报