zoukankan      html  css  js  c++  java
  • javascript中this指针探讨

    javascript中this指针探讨

     

      javascript是一门类java语言有很多跟java相类似的特点,但也仅是类似而已,真正使用中还是有很大的差别。this指针常常让很多初学者抓狂,本人也曾为此困惑不解,查找过很多资料,今天在这里总结一下,希望能帮助后来者更快驯服这只拦路虎。网上有很多讲解this指针的文章其中不乏精品,以我看来了解this指针关键在于掌握javascript中函数的四种调用模式。那么什么是调用?调用指的是跟在任何产生一个函数值的表达式之后使用"()",obj.f()这种方式成为调用,obj.f这种方式称为访问。

      一、方法调用模式:

      在该调用模式中函数作为一个对象的方法被调用:obj.fun()。当函数以此种形式被调用时this指针绑定到调用该方法的对象上即obj。

    复制代码
     1 var myObj = {
     2   value: 0,
     3   increase: function(){
     4     this.value++;
     5     console.log(this.value);
     6   }
     7 };
     8 // this绑定到myObj对象上
     9 myObj.increase(); // 1
    10 
    11 myObj2 = {
    12   value: 10
    13 };
    14 myObj2.increase = myObj.increase;// myObj2与myObj的increase指向同一函数引用地址
    15 // this绑定到myObj2对象上
    16 myObj2.increase(); // 11
    复制代码

      所以在将一个html元素的某一事件绑定某一函数时,若函数中使用this指针,则this指针会被绑定到该元素上。

    1 var ele1 = document.getElementById('id');
    2 ele1.addEventListener('click', myObj.increase, false);
    3 // 该绑定相当于
    4 ele1.onclick = myObj.increase;
    5 // 事件触发时即相当于调用click方法
    6 ele1.click(); // 与上文中myObj2.increase一个道理,若ele1中没有value属性则会报错

      二、函数调用模式:

      当函数没有当做方法调用即没有被一个对象通过点语法,这时它被当做一个函数来调用。以此模式调用函数时,this被绑定到全局对象。

    复制代码
     1 var value = -10;
     2 var myObj = {
     3   value: 0,
     4   increase: function(){
     5     this.value++;
     6     console.log(this.value);
     7   }
     8 };
     9 // this绑定到myObj对象上
    10 myObj.increase(); // 1
    11 
    12 var gInc = myObj.increase;
    13 gInc(); // -9 this绑定到window对象上
    复制代码

      所以在方法中使用内部函数时要特别注意,下例中other函数中的this并未绑定到myObj对象上

    复制代码
    var value = -10;
    var myObj = {
      value: 0,
      increase: function(){
        this.value++;
        console.log(this.value);
        var other = function(){
          this.value++;
          console.log(this.value); 
        };
        other();// -9, 这时other中的this绑定到window对象上
      }
    };
    // this绑定到myObj对象上
    myObj.increase(); // 1
    
    var gInc = myObj.increase;
    gInc(); // -8
    ///////////////
    //1
    //-9
    //-8
    //-7
    复制代码

      幸运的是我们可以使用以下方式来在other中访问myObj对象:

    复制代码
     1 var myObj = {
     2   value: 0,
     3   increase: function(){
     4     this.value++;
     5     console.log(this.value);
     6     var that = this;
     7     var other = function(){
     8       that.value++;
     9       console.log(that.value); 
    10     };
    11     other();// -9, 这时other中的this绑定到window对象上
    12   }
    13 };
    14 // this绑定到myObj对象上
    15 myObj.increase(); // 1
    16 //////////////
    17 //1
    18 //2
    复制代码

      作为浏览器兼容性中很重要的一条:element.attachEvent绑定事件方法,当该事件触发时this指针并未绑定到element对象上,而是绑定到了window对象上,原因在于IE中事件触发时,响应函数是以一个独立函数即函数调用模式来调用的

      三、构造器模式调用:

      如果在一个函数前面加上new调用则成为构造器模式调用。使用new运算符,会产生一个连接到该函数prototype的新对象,this指针则被绑定到这个新对象上。

    复制代码
    1 var P = function(n){
    2   this.name = n;
    3 }
    4 P.prototype.getName = function(){
    5   console.log(this.name);
    6 }
    7 var p = new P('woodtree'); // 这时P中的this对象呗绑定p指向的对象引用上
    8 p.getName();// woodtree
    复制代码

      同时new运算符还会改变函数的返回值。以函数调用模式调用P即P()返回undefined,而通过new运算符则返回一个新对象。new运算符类似于以下Function.prototype.create函数:

    复制代码
     1 var P = function(n){
     2   this.name = n;
     3 }
     4 P.prototype.getName = function(){
     5   console.log(this.name);
     6 }
     7 var p = new P('woodtree');
     8 p.getName();
     9 
    10 Object.prototype.create = Object.create || function(proto){
    11   var F = function(){};
    12   F.prototype = proto;
    13   return new F();
    14 }
    15 
    16 Function.prototype.create = function(){
    17   var that = object.create(this.prototype);
    18   var obj = this.apply(that, arguments);
    19 
    20   return obj || that;
    21 }
    22 var p2 = P.create('hello new');
    23 p2.getName(); // hello new
    复制代码

      四、apply、call模式调用:

      javascript中函数对象继承自Object亦可以拥有方法。call跟apply允许我们选择this的绑定对象。这两个方法的区别在于apply第二个参数必须是一个数组或者类数组对象即拥有length属性(arguments、NodeList、HTMLElementCollection等),而call除了第一个参数为要绑定this的对象外,后可跟无数的参数,参数之间用逗号间隔。

    复制代码
     1 var P = function(n){
     2   this.name = n;
     3 }
     4 P.prototype.getNameAndAge = function(age){
     5   console.log(this.name + age);
     6 }
     7 
     8 P.prototype.getNameAndAge.call({
     9   name: 'catboat'
    10 }, 99);
    11 P.prototype.getNameAndAge.apply({
    12   name: 'lanuch'
    13 }, [99]);
    复制代码

      通过使用apply与call方法我们可以自行实现ES5中的bind函数

    复制代码
     1 var P = function(n){
     2   this.name = n;
     3 }
     4 P.prototype.getNameAndAge = function(age, age2){
     5   console.log(this.name + age + age2);
     6 }
     7 
     8 P.prototype.getNameAndAge.call({
     9   name: 'catboat'
    10 }, 99);
    11 P.prototype.getNameAndAge.apply({
    12   name: 'lanuch'
    13 }, [99]);
    14 
    15 Function.prototype.bindContext = function(that){
    16   var _method = this,
    17   slice = Array.prototype.slice,
    18   args = slice.call(arguments, 1);
    19 
    20   return function(){
    21     _method.apply(that, Array.prototype.concat.apply(args, arguments));
    22   }
    23 };
    24 
    25 var f1 = P.prototype.getNameAndAge.bindContext({
    26   name: 'barque'
    27 }, 88);
    28 f1(9);
    复制代码

      同样我们也可以解决IE中事件触发时,this指针问题(以下代码来自《Javascript框架设计》):

    1 var addEvent = document.addEventListener ? function(el, type, fn, capture){
    2   return el.addEventListener(type, fn, capture);
    3 } : function(el, type, fn){
    4   el.attachEvent('on' + type, fn.bindContext(el, event));
    5 }
     
     
     
     
     
     
  • 相关阅读:
    DB2数据库BACKUP PENDING状态(修改日志模式导致)(转)
    JAVA调用WebService实例
    eclipse启动报JVM terminated. Exit code=-1的解决方法
    JAVA使用Dom4j组装、解析XML
    任务调度IBM Tivoli Workload Scheduler(TWS)
    Java遍历Map数据的几种方式
    谈谈我对Log4j2以外的感想
    ESQL中添加JMS参数
    node.js-node-inspector调试
    前端-浏览器内核
  • 原文地址:https://www.cnblogs.com/xueandsi/p/5909989.html
Copyright © 2011-2022 走看看