【 JavaScript 基础】之this关键字

前言

JS 是一种脚本语言,因此被很多人认为是简单易学的。然而情况可能与之相悖,JS 遵从函数式编程、闭包、基于原型的继承等高级功能。本文介绍一下JS中的 this 关键字,可以这样说,正确掌握了 JS 中的 this 关键字,才算迈入了 JS 这门语言的门槛。

注: 本文采用部分 es6 进行代码分析

Java工程师所熟识的this

在 Java 中定义类经常会使用 this 关键字,多数情况下是为了避免命名冲突,比如在下面例子的中,定义一个 Image 类,很自然的,大家会使用 width、height 为其属性或成员变量命名,在构造函数中,使用 width、height 为参数命名。无论哪种情况,this 的含义是一样的,均指当前类对象,当调用构造方法时全局变量width、height的值会被修改。

    public class Image {
        private int width = 0;
        private int height = 0;

        public Image(int width, int height) {
            this.width = width;
            this.height = height;
        }

        public void println() {
            System.out.println("width = " + this.width);
            System.out.println("height = " + this.height);
        }

    }

调用方式如下:

        Image image = new Image(10, 10);
        image.println();

输出结果:

width = 10
height = 10

Process finished with exit code 0

可以看得出来this.x 与 this.y 直接修改的全局变量的值,也证明了我们上面的观点~

JS语言中的 this

由于JS等脚本语言运行期进行解释的特性,JS 中的 this 含义要丰富得多,它可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。

JS 中函数的调用有以下几种方式:

1、作为对象方法调用
2、作为函数调用
3、作为构造函数调用
4、使用 apply 或 call 调用

接下来我们按照调用方式的不同,分别讨论 this 的含义。

作为对象方法调用

var image = { 
   width : 0, 
   height : 0, 
   update : function(width, height) { 
     this.width = this.width + width
     this.height = this.height + height
   } 
 }

 // this 绑定到当前对象,即 image 对象
 // 执行此方法后image的width与Height属性值变为1
 image.update(1, 1) 

作为函数调用

当调用函数时,此时 this 绑定到全局对象,在浏览器中,window 就是该全局对象,例如下面:setLocalValue 函数被调用时,this 被绑定到全局对象,接下来执行赋值语句,相当于隐式的声明了一个全局变量,这显然不是调用者希望的效果~

 function setLocalValue(value) { 
   this.localValue = value
 } 

 setLocalValue(5)
 
 // localValue 已经声明成一个值为 5 的全局变量
 console.log(localValue) // ==> 5

对于内部函数,即声明在一个函数体内的函数,这种绑定到全局对象的方式会衍生出一个新的问题,我们仍然以前面提到的 image 对象为例,这次我们希望在 update 方法内定义两个函数,分别将 width、height 属性进行修改。结果可能出乎大家意料,不仅 image 对象没有移动,反而多出两个全局变量 width、height。

var image = { 
  width : 0, 
  height : 0, 
  update : function(width, height) { 
    // 内部函数
    var updateWidth = function(width) { 
      //this 绑定到了哪里?
      this.width = width;
    } 
    // 内部函数
    var updateHeight = function(height) { 
      //this 绑定到了哪里?
      this.height = height;
    }
    
    updateWidth(width) 
    updateHeight(height) 
  } 
}
 
 image.update(1, 1)
 
 console.log(image.width) // ==> 0
 console.log(image.height) // ==> 0
 console.log(width) // ==> 1
 console.log(height) // ==> 1

这属于 JS 语言的设计缺陷,正确的设计方式是内部函数的 this 应该绑定到其外层函数对应的对象上,为了规避这一设计缺陷,我们一般采用变量替换的方法,该变量草民习惯命名为成 self~

var image = { 
  width : 0, 
  height : 0, 
  update : function(width, height) { 
    var self = this
    // 内部函数
    var updateWidth = function(width) { 
      self.width = width;
    } 
    // 内部函数
    var updateHeight = function(height) { 
      self.height = height;
    }
    
    updateWidth(width) 
    updateHeight(height) 
  } 
}
 
 image.update(1, 1)
 
 console.log(image.width) // ==> 1
 console.log(image.height) // ==> 1

这样就达到了我们想要的效果~

作为构造函数调用

JS 支持面向对象编程,但与主流的面向对象式编程语言不同。

:es6之前JS 并没有类(class)的概念,而是使用基于原型(prototype)的继承方式,JS 中的构造函数也很特殊,如果不使用 new 调用,则和普通函数一样,作为又一项约定俗成的准则,构造函数以大写字母开头,提醒调用者使用正确的方式调用,如下es5示例。

:es6之后支持了class的概念,重写constructor方法,this 绑定到新创建的对象上。

es5示例 :

function Image(width, height){ 
    this.width = width
    this.height = height
}

var img1 = new Image(10, 10)

es6 示例 :

class Image {

  constructor(width, height) {
    this.width = width
    this.height = height
  }

}

 let img1 = new Image(10, 10)

使用 apply 或 call 调用

此次着重强调一下,在 JS 语言中函数也是对象,对象则有行为(方法),apply 和 call 就是函数对象的方法。这两个方法功能超级强大,它们允许切换函数执行的上下文环境(context),即 this 指向的对象,在很多JS库中也得到了广泛应用~

class Image {

  constructor(width, height) {
    this.width = width
    this.height = height
  }

  update(width, height) { 
     this.width = width
     this.height = height
  } 

}

 let img1 = new Image(0, 0)
 let img2 = {width: 0, height: 0}
 img1.update(10, 10)
 
 // img2 width、height ==> 20
 img1.update.apply(img2, [20, 20]) 
 
 // img2 width、height ==> 20
 img1.update.call(img2, 20, 20)

在上面的例子中,我们使用构造函数生成了一个对象 img1,该对象同时具有 update 方法,同时定义了另一个对象 img2,使用 apply 可以将 img1 的方法应用到 img2 上,这时候 this 也被绑定到对象 img2 上。

结语:

JS之this关键字就介绍到这里,谢谢大家的观看,希望对大家有所帮助~

    原文作者:王永迪
    原文地址: https://www.jianshu.com/p/224eefbc2158
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞