资讯专栏INFORMATION COLUMN

this详解

Kahn / 1180人阅读

摘要:的作用这段代码可以在不同的上下文对象中重复使用函数和不用针对每个对象编写不同版本的函数。显然从字面意思来理解行不通执行时的确向函数对象添加了一个属性。的绑定和函数声明的位置没有任何关系,只取决于函数调用的方式调用位置。

this的作用
function identify() {
  return this.name.toUpperCase()
}

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

var me = {
  name: "aa"
}
var you  = {
  name: "bb"
}
identify.call(me) // AA
identify.call(you) // BB

speak.call(me) // HelloAA
speak.call(you) // HelloBB

这段代码可以在不同的上下文对象中重复使用函数identify()和speak()、不用针对每个对象编写不同版本的函数。
如果不使用this,那就需要给identify()和speak()显示传入一个上下文对象

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

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

identify(you) // BB
speak(me) //HelloAA

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

this是什么

人们很容易把this理解成指向函数自身,从英文翻译上理解似乎是对的,下面看个例子:

function foo(num) {
  console.log("foo" + num)
  this.count++
  console.log(this === window) // true
}
foo.count = 0
var i;
for (i = 0; i < 10; i++) {
  if (i > 5) {
    foo(i)
  }
}
console.log(foo.count) // 0

console.log语句产生了4条输出,证明foo(...)确实被调用了4次,但是foo.count任然是0。显然从字面意思来理解this行不通
执行foo.count = 0时的确向函数对象foo添加了一个属性count。但是函数内部代码this.count的this并不是指向那个函数对象,指向的是全局对象window

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

绑定规则 默认绑定

首先介绍的是最常用的函数调用类型:独立函数调用。可以把这条规则看作是无法应用其他规则时的默认规则,举个例子:

function foo() {
  console.log(this.a) //2
}
var a = 2
foo()

当调用foo()时,this.a被解析成了全局变量a,因为此时foo()是直接使用不带任何修饰的函数引用进行调用的,只能用默认绑定,无法应用其他规则
但是当严格模式,不能将全局对象应用于默认绑定,this会绑定到undefined

隐式绑定

另一条需要考虑的规则是调用位置是否有上下文对象。举个例子

function foo() {
  console.log(this.a)
}
var obj = {
  a: 2,
  foo: foo
}
obj.foo() // 2

当foo()被调用时,它的前面加上了对obj的引用,当函数引用有上下文对象是,隐式绑定规则会把函数调用中this绑定到这个上下文对象。
对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。举个例子

function foo() {
  console.log(this.a)
}
var obj2 = {
  a: 42,
  foo: foo
}
var obj1 = {
  a: 2,
  obj2: obj2
}
obj1.obj2.foo() // 42
隐式丢失

隐式绑定最常见的一个问题就是被隐式绑定的函数会丢失绑定对象,也就是会所它会应用默认绑定,从而把this绑定到全局对象或者undefine上,取决于是否严格模式,举个例子:

function foo() {
  console.log(this.a)
}
var obj = {
  a: 2,
  foo: foo
}

var bar = obj.foo;
var a = "global"
bar() //相当于执行 foo() "global"

虽然bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定

显示绑定

javascript中提供的显示绑定的方法就是大家都非常熟悉的call(...)、apply(...)和bind(...)方法,下面就简单介绍一下它们的用法:
call的语法为:

fun.call(thisArg[, arg1[, arg2[, ...]]])

apply的语法为:

fun.apply(thisArg, [argsArray])

它们的第一个参数对象是一个对象,是个this准备的,接着在调用函数将其绑定到this。第二个参数 call 方法接受的是若干个参数列表,而apply接收的是一个包含多个参数的数组。

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。因此:bind 是创建一个新的函数,我们必须要手动去调用,举个例子:

var a ={
  fn : function (a,b) {
    console.log( a + b)
  }
}

var b = a.fn;
b.bind(a,1,2)() // 3
new绑定

使用new来调用函数,会自动执行下面的操作

创建(或者说构造)一个全新的对象

这个新对象会被执行[[Prototype]]连接

这个对象会绑定到函数调用的this

如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

举个例子:

function foo(a) {
  this.a = a
}
var bar = new foo(2)
console.log(bar.a) // 2

使用new来调用foo(...)时,会构造一个新对象并把它绑定到foo(...)调用中的this上

绑定优先级

函数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象

函数是否通过call、apply、bind(显示绑定)?如果是的话,this绑定是指定的对象

函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象

如果都不是,使用默认绑定,如果在严格模式下就绑定到undefined,否则绑定到全局对象

ES6中this指向

ES6中的箭头函数并不会使用上述的绑定规则,而是根据当前的词法作用域来决定this,具体来说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么)举个例子:

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  setInterval(() => this.s1++, 1000);
  setInterval(function () {
    this.s2++;
  }, 1000);
}
var timer = new Timer();

setTimeout(() => console.log("s1: ", timer.s1), 1100); // 1
setTimeout(() => console.log("s2: ", timer.s2), 1100); // 0

上例中s1的值是在箭头函数中,会继承Timer函数作用域中的this,而s2在普通函数中,根据之前的绑定绑定规则可以看出此时的this会执行默认的绑定规则绑定到全局对象上

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94254.html

相关文章

  • JavaScript 中 this详解

    摘要:作为构造函数调用中没有类,但是可以从构造器中创建对象,并提供了运算符来进行调用该构造器。构造器的外表跟普通函数一样,大部分的函数都可以当做构造器使用。如果构造函数显式的返回一个对象,那么则会指向该对象。 this 的指向 this 是 js 中定义的关键字,它自动定义于每一个函数域内,但是它的指向却让人很迷惑。在实际应用中,this 的指向大致可以分为以下四种情况。 1.作为普通函数调...

    cyrils 评论0 收藏0
  • JavaScript之this对象详解

    摘要:再来看一个小的示例淘宝腾讯淘宝为什么输出的依然是淘宝呢调用的是对象中的方法,方法里面有一个定时器,而定时器的一个参数是这里的指的就是的对象,然后方法里面有调用了,但是定时器中的指的是对象,所以最终调用的是对象中。 1.看前热身 看一段代码 var name = javascript; var obj = { name:js, foo:f...

    Integ 评论0 收藏0
  • 20190725笔记-apply详解

    摘要:语法参数这个对象将替代类里的对象可选在函数运行时使用的值。如果该参数的值为或,则表示不需要传入任何参数。更简单的讲就是将和传入函数执行。 学了那么久前端,对apply、call这两个函数的用法,还不是很掌握。今天看了很多网上的文章,我总结和归纳下用法。 Function.prototype.apply() apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数...

    wzyplus 评论0 收藏0
  • javascript this指针详解

    摘要:但是有一个总的原则,那就是指的是,调用函数的那个对象使用主要分四种情况,讨论下指针的用法和注意事项一纯粹的函数调用这是函数的最通常用法,属于全局性调用,因此就代表全局对象。 this是Javascript语言的一个关键字它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对...

    graf 评论0 收藏0
  • javascript this指针详解

    摘要:但是有一个总的原则,那就是指的是,调用函数的那个对象使用主要分四种情况,讨论下指针的用法和注意事项一纯粹的函数调用这是函数的最通常用法,属于全局性调用,因此就代表全局对象。 this是Javascript语言的一个关键字它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对...

    AlphaWallet 评论0 收藏0
  • [面试专题]ES6之箭头函数详解

    摘要:使用或调用由于已经在词法层面完成了绑定,通过或方法调用一个函数时,只是传入了参数而已,对并没有什么影响箭头函数不会在其内部暴露出参数等等,都不会指向箭头函数的,而是指向了箭头函数所在作用域的一个名为的值如果有的话,否则,就是。 ES6之箭头函数 标签(空格分隔): 未分类 返回值 单行函数体默认返回改行计算结果, 多行需要指定返回值 let c = (a,b)=>a+b; conso...

    Caicloud 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<