this是Javascript语言的一个关键字。
它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。比如,
  function test(){
    this.x = 1;
  }
随着函数使用场合的不同,this的值会发生变化。
有一个总的原则,那就是this指的是,调用函数的那个对象。
下面分四种情况,详细讨论this的用法:
情况一:纯粹的函数调用

这是函数的最通常用法,属于全局性调用,因此this就代表全局对象Global。

1)请看下面这段代码,它的运行结果是1。

  

function test(){
    this.x = 1;
    alert(this.x);
  }
  test(); // 1

为了证明this就是全局对象,我对代码做一些改变:

  

var x = 1;
  function test(){
    alert(this.x);
  }
  test(); // 1

运行结果还是1。再变一下:
  

var x = 1;
  function test(){
    this.x = 0;
  }
  test();
alert(x); //0

2)接下来分析匿名函数下的情况(博客内容外的自添加):

var name="the window";
var object={
    name:"My object",
    getNameFunc:function(){
        return function(){
            return this.name; //没有被直接调用,此匿名函数的执行环境具有全局性
        };    }
};
alert(object.getNameFunc()());//the window(非严格模式下)

情况二:作为对象方法的调用

函数还可以作为某个对象的方法调用,这时this就指这个上级对象。

  

function test(){
    alert(this.x);
  }
  var o = {};
  o.x = 1;
  o.m = test;
  o.m(); // 1

情况三 作为构造函数调用

所谓构造函数,就是通过这个函数生成一个新对象(object)。这时,this就指这个新对象。

  

function test(){
    this.x = 1;
  }
  var o = new test();
  alert(o.x); // 1

运行结果为1。为了表明这时this不是全局对象,我对代码做一些改变:
 

 

var x = 2;
      function test(){
        this.x = 1;
      }
      var o = new test();
      alert(x); //2

运行结果为2,表明全局变量x的值根本没变。

情况四 apply调用

apply()是函数对象的一个方法,它的作用是改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。因此,this指的就是这第一个参数。

  

var x = 0;
  function test(){
    alert(this.x);
  }
  var o={};
  o.x = 1;
  o.m = test;
  o.m.apply(); //0

apply()的参数为空时,默认调用全局对象。因此,这时的运行结果为0,证明this指的是全局对象。
如果把最后一行代码修改为
  

o.m.apply(o); //1

运行结果就变成了1,证明了这时this代表的是对象o。

                                ----------摘自阮一峰博客

另附笔者见解:

This对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数作为某个对象的方法调用时,this等于那个对象。不过,匿名函数的执行环境具有全局性,因此其this通常指向window。但是由于闭包编写方式不同,结果没有那么明显。
别忘了:有一个总的原则,那就是this指的是,调用函数的那个对象。

例1. 匿名函数没有被直接调用,匿名函数的执行环境具有全局性,this指的是window对象 

var name="the window";
var object={
    name:"My object",
    getNameFunc:function(){
        return function(){
            return this.name;
        };//没有被直接调用,此匿名函数的执行环境具有全局性
    }
};

alert(object.getNameFunc()());//the window(非严格模式下)

例2.匿名函数被直接调用,this指的是调用它的对象

var name="the window";
var object={
    name:"My object",
    getNameFunc:function(){
            return this.name;
        };//被getNameFunc(也就是object)调用
    }
};
alert(object.getNameFunc()());//My object(非严格模式下)

例3.通过that绑定执行环境对象(this是关键字,而that不是关键字)

var name="the window";
var object={
    name:"My object",
getNameFunc:function(){
var that=this;//通过that绑定了object对象 ;object <--getNameFunc(name)
        return function(){
            return that.name;//创建闭包,返回that.name
        };//object下的name
    }
};
alert(object.getNameFunc()());//My object(非严格模式下)

模仿块级作用域(私有作用域):
语法如下:



(function(){
//这里是块级作用域
})();

以上代码定义并且立即调用了一个匿名函数。将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一对括号会立即调用这个函数。
类似于:

var someFunction=function(){
//这里是块级及作用域
};
someFunction();

这里定义了一个函数(匿名函数,并把值赋给someFunction)然后立即调用了它(在函数名称后面添加一对括号)。

下面来看另一种不加括号的情况:

function(){//dosomething}();
例:function (){alert("Hi")}();

这段代码会导致语法错误,是因为javascript将function关键字当作一个函数声明的开始,而函数声明后面不能跟圆括号。而表达式后面可以跟圆括号,要将函数声明变成表达式,只要向下面那样给它加一对圆括号即可:

(function(){
//这里是块及作用域
})();

如:(function (){alert("Hi")}());

注:

1.result=function(){//dosomething}(); 这个匿名函数后加括号不会报错而且匿名函数会立即执行。
2.result=function(){//dosomething}()与function(){//dosomething}()两个语句完全不同,前者是有赋值的。
3.可行原因是这里的赋值js实际上把匿名函数当作表达式处理了,表达式后面可以加括号。
而且在function(){//dosomething}()前面加“-“、”!“等运算符还会根据运算规则改变赋给result的值。
4.result=
  1. function(){//dosomething}();
    2.!function(){ // do something }();
    3.~ function() {}();
    4.+ function() {}();
    5.- function() {}()
    原理是语句function(){//dosomething}()都被当作表达式处理了(赋值前计算表达式的值),就是2、3、4、5例可以自执行,自执行的原因也是function(){//dosomething}()由于前面的符号被当作表达式处理了

私有作用域实例:

function outputNumbers(count){
    (function(){
        for(var i=0;i<count;i++){
            alert(i);//块级作用域
        }
    })();
    alert(i);//会导致一个错误,i已经被销毁了
}
outputNumbers(5);//0,1,2,3,4
                //抛出错误

面试题解析:

1.
var foo = {
    bar: function() { return this.baz; },
    baz: 1
  };
  (function(){
    return typeof arguments[0]();
  })(foo.bar);
答案:"undefined"

在arguments[0]()中执行了一个方法,arguments[0]就是foo.bar方法

注意: foo.bar作为整体传入函数中,但是foo.bar中的this是没有绑定到foo,虽然 foo.bar 传递给了函数,但是真正执行的时候,函数 bar 的上下文环境是 arguments ,并不是 foo。(foo.bar作为整体的传递方式解除了foo对bar的调用作用)

arguemnts[0] 可以理解为 arguments.0(不过写代码就不要这样了,语法会错误的),所以这样看来,上下文环境是 arguemnts 就没问题了,所以在执行baz的时候自然this就是window了,window 上没有baz属性,返回的就是undefined, typeof调用的话就转换成"undefined"了

这里的 this 指的是 arguments,经测试确实如此:

2.

  var foo = {
    bar: function(){ return this.baz; },
    baz: 1
  }
  typeof (f = foo.bar)();
答案:"undefined"
类似于
var foo = { 
  bar: function(){ return this.baz; }, 
  baz: 1 
} 
f = foo.bar; 
typeof f();
把foo.bar存储给f然后调用,所以this在foo.bar引用的是全局对象,所以就没有baz属性了
换句话说:foo.bar执行的时候上下文是 foo,但是当 把 foo.bar 赋值给 f 的时候,f 的上下文环境是 window ,是没有 baz 的,所以是 ”undefined"。

解决方案:利用闭包或者bind()

//函数绑定bind()
function bind(fn,context){//返回闭包
    return function(){
        return fn.apply(context,arguments);//arguments指函数内部的而非bind的
    }
}
//测试
var handler={
    message : "Event Handler",
    handleClick : function(event){
        alert(this.message);
    }
}
//var documentFragment=document.createDocumentFragment();
var text='<button id="button">按钮</button>';
document.body.innerHTML=text;
var btn=document.getElementsByTagName("button")[0];
EventUtil.addHandler(btn,"click",bind(handler.handleClick,handler));

specialcoder
2.2k 声望170 粉丝

前端 设计 摄影 文学