2.1 关于this

一、为什么要用 this

使用了this

function identify() {
    return this.name.toUpperCase()
}

function speak() {
    var greeting = "Hello, I'm " + identify.call(this)
    console.log(greeting)
}

var me = {
    name:"Kyle"
}

var you = {
    name:"Reader"
}

identify.call(me)
identify.call(you)

speak.call(me)  	// Hello, I'm KYLE
speak.call(you)	// Hello, I'm READER

这段代码可以在不同的上下文对象(meyou)中重复使用函数 identify()speak(), 不用针对每个对象编写不同版本的函数。

不使用 this
如果不使用this,那就需要给 identify()speak()显式传入一个上下文对象。

function identify(context) {
    return context.name.toUpperCase()
}

function speak(context) {
    var greeting = "Hello, I'm " + identify(context)
    console.log(greeting)
}

var me = {
    name:"Kyle"
}

var you = {
    name:"Reader"
}

identify(me)
identify(you)

speak(me)		//Hello, I'm KYLE
speak(you) 		//Hello, I'm READER

对比总结:this 提供了一种更优雅的方式来隐式“传递”一个对象引用,因此可以将 API 设计得更加简洁并且易于复用。随着使用的模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱,使用 this则不会这样。

二、对 this 的误解

1. 指向自身:容易把 this 理解成指向函数本身。

function foo(num) {

    console.log("foo:" + num)

    //记录 foo 被调用的次数
    this.count++
}
//执行这句时,的确像函数对象 foo 添加了一个属性 count 。
//但是函数内部代码 this.count 中的 this 并不是指向那个函数对象,所以虽然属性名相同,根对象却并不相同。
foo.count = 0; 

var i;
for (i = 0; i < 10; i++) {
    if (i > 5) {
        foo(i);
    }
}

console.log(foo.count)
-----------------------------------------------------------------------------------
> foo:6
> foo:7
> foo:8
> foo:9
> 0

如果要从函数对象内容引用它自身,那只使用 this 是不够的。一般来说需要通过一个指向函数对象的词法标识符(变量)来引用它。

// 这是个具名函数,在它的内部可以用函数名字来引用自身
function foo(num) {
   foo.count = 4 // foo 指向它自身
}

setTimeout(function(){
    // 匿名(没有名字的)函数无法指向自身
},10)

所以上述“使用 this 的例子”可以使用函数标识符替代 this 来引用函数对象:

function foo(num) {
    console.log("foo:" + num)
    //是使用 foo 标识符替代 this 来引用函数
    foo.count++
}

foo.count = 0; 

var i;
for (i = 0; i < 10; i++) {
    if (i > 5) {
        foo(i);
    }
}

console.log(foo.count)
----------------------------------------------------------
> foo:6
> foo:7
> foo:8
> foo:9
> 4

但是这种方法回避了 this 的问题,并且完全依赖于变量 foo 的词法作用域。
接下来是强制使用 this 指向函数对象的方法:

function foo(num) {
    console.log("foo:" + num)
    //注意:在当前的调用方式下,this 确实指向 foo
    this.count++
}

foo.count = 0; 

var i;
for (i = 0; i < 10; i++) {
    if (i > 5) {
    	// 使用 call(...) 可以确保 this 指向函数对象 foo 本身
        foo.call(foo,i);
    }
}

console.log(foo.count)
----------------------------------------------------------
> foo:6
> foo:7
> foo:8
> foo:9
> 4

2.它的作用域:this 指向函数的作用域。

需要明确的是,this 在任何情况下都不指向函数的词法作用域。在 JavaScript 内部,作用域确实和对象类似,可见的标识符都是它的属性。但是作用域“对象”无法通过 JavaScript 代码访问,它存在于JavaScript 引擎内部。

使用 this 来隐式引用函数的词法作用域,错误栗子:

function foo(){
    var a = 2;
    this.bar()
}

function bar(){
    console.log(this.a)
}

foo() 	// ReferenceError: a is not defined

解释:

  1. 这段代码视图通过 this.bar() 来引用 bar() 函数。这是决不能成功的。调用 bar()最自然的方法是省略前面的 this, 直接使用词法引用标识符。
  2. 编写这段代码的开发者视图使用 this 联通 foo()bar() 的词法作用域,从而让 bar() 可以访问 foo() 作用域里的变量 a。 这是不可能实现的,不能使用 this 来引用一个词法作用域内部的东西。

每当想要把 this 和词法作用域的查找混合使用时,一定要提醒自己,这是无法实现的。

三、this 到底是什么

this 是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。
当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this 就是记录的其中一个属性,会在函数执行的过程中用到。

四、总结

  1. this 既不指向函数自身也不指向函数的词法作用域。
  2. this 实际上是在函数被调用时发生的绑定, 它指向什么完全取决于函数在哪里被调用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值