【 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关键字就介绍到这里,谢谢大家的观看,希望对大家有所帮助~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容