关于JavaScript的this

来源:互联网 发布:拼接屏软件 编辑:程序博客网 时间:2024/05/29 04:45
  this这个概念在很多流行语言里都有,大家的定义都很一致,也就是运行时的实例本身,但是在JavaScript这里就不一样了。this是函数里的当前引用(全部代码你可以看成是在宿主对象window下的一个大匿名函数里,就像require的实现那样),有一种说法是JavaScript里的this是调用者对象,但这个并不贴切。比如下面的代码:
   
var o = {};
o.f = function() {
    var ff = function() {
        console.log(this);
    };
    ff();
    console.log(this);
};
o.f(); // window   &  o 
     
变量ff不是全局变量,执行环境是在o.f里面,一定要理解成ff()调用者是window,下面一句又回到o调用,这个也太别扭了。那么我们应该如何理顺这种关系呢?
  首先, 在JavaScript的运行时里,一切存在单位皆是对象(实例)。这些对象不是孤立存在的,它们之间有两种类型的关系。一类是对象能力的回溯关系(原型链);一类是对象引用的组织关系(对象属性),也就是摆放在哪儿。而this指向的正是其摆放位置对象。比如上例中的f在对象o里,里面的this就是o。o和ff没有明确指定摆放位置,在标准模式下它们会被摆放在宿主对象window里,this自然就是window了。那如果我们执行如下代码会怎么样呢:
 
var of = o.f;
of(); // window  &  window
 of和o.f是同一个函数的两个引用,这里可以看出this即是引用位置对象。继续代码: 
 
o.oo = {
    g: function() {
        console.log(this);
    }
};
o.oo.g(); // o.oo 
不用解释了吧。继续代码:
 
var f1 = function() {
    console.log(this);
};
var o1 = new f1(); // f1 
这个怎么理解呢?我们把引擎的动作用如下的伪代码描述:
//  
var f1 = function() {
    console.log(this);
};
var o1 = {};
o1.__proto__ = {
    constructor: f1
};
o1.constructor();
不用解释了吧。继续代码: 
    
o.f2 = function() {
    var ff = () => {
        console.log(this);
    };
    ff();
    console.log(this);
};
o.f2(); //     o
 Why? 这个o.f2和之前的o.f的区别就是把函数的书写形式变了一下,箭头函数里输出的为什么不是window呢?“箭头函数”的学名叫lambda表达式(lambda expression),它像函数一样拥有一个独立的作用域,但是并不具备函数的各种特性。所以箭头函数里的this也就等同于此“函数”所在位置的this。OK,继续code:
  
o.oo.g1 = function() {
    setTimeout(this.g, 1000); // call o.oo.g()
};
o.oo.g1(); // window
 这里不会像直接执行o.oo.g()那样打印o.oo对象了,因为setTimeout向宿主环境(window)注册了一个执行体函数,window会把这个执行体保存在自己的一个匿名属性里,将来由宿主对象执行时打印的就是window。但是下面这个定时器又不一样了:
 
o.oo.g2 = function() {
    console.log(this);
    setTimeout(()=>{ console.log(this); }, 1000);
};
o.oo.g2(); //  o.oo 
 这个定时器执行的时候为什么不是打印window呢?前书说过,lambda表达式不具备函数特性,也不存在自己的this,这里这个this其实是因为闭包特性顺带过来的。如有疑问可以换一个普通变量看看即知。

  诸如call、apply、bind这些都是人工指定this,当然您指啥就是啥。如果指定对象是undefine或者null之类,则仍然遵守前述规则指向宿主对象window(正常模式)。
 
总结:
一、以上论述纯属推断,并未参考源代码的实际实现。因此如有雷同,纯属巧合呲牙  。我们从正向和反向看待同一个事物的时候,有时能看到不同的东西。
二、以上推断出于技术研究的动机,若出于实用目的,我认为可以用更加常规的代码组织方式,并不必要把这些东西剥得这么清楚。就如同我们想写一封信,并不需要会写四种“回”字。
0 0
原创粉丝点击