关于javascript中的this、apply、call、bind

关于javascript中的this、apply、call、bind

来自网络

2018-09-27 08:54 阅读 550 喜欢 0 理解js的this apply和call

隐式绑定的 this

this 实际上是在函数被调用时绑定的,它指向什么完全取决于函数的调用方式。

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

var foo2 = obj.foo
obj.foo() // 1
foo2() // undefined

如果没有指定函数的运行对象,默认的 this 会隐式的绑定到运行环境的全局对象上。

function foo() {
  console.log(this.a)
}
a = 'global'
foo() // global

看一个常见但是有点出乎意料的的例子,如果是回调函数,即使你传入了 obj.foo 还是会丢失 this

function foo() {
  console.log(this.a)
}
function doFoo(fn) {
  fn()
}
var obj = { a: 1, foo: foo }
a = "global"
doFoo(obj.foo) // global

如果是链式调用呢,则是最后哪个对象调用了这个方法,this 指向谁。

function foo() {
  console.log(this.a);
}
var obj2 = { a: 11, foo: foo }
var obj1 = { a: 1, obj2: obj2 }
obj1.obj2.foo(); // 11

其实 this 的指向都有规律可言,在隐式绑定的 this 中,this 绑定的是调用它的对像。我们回过头解释上面例子。

第一个例子的 foo2() 和第二个例子的 foo() 其实是在 window (global) 对象上运行的,对应的打印值就合乎情理了。第三个例子涉及 JS 执行的原理,传入的 obj.foo 被赋值到 fn 上,所以本质上是 fn = obj.foo; window.fn(),因此 this 指向了 window

显式绑定的 this

隐式绑定的 this 能为我们带来很多灵活性,但是有时我们需要显式的指定函数运行的 this

比如 apply、call、bind 这三个绑定在 Function.prototype 上的函数(关于 prototype 我们会在后面的章节提到),让我们先看看具体 API。

fun.apply(thisArg, [argsArray])
fun.call(thisArg, arg1, arg2, ...)
fun.bind(thisArg[, arg1[, arg2[, ...]]])

它们的语法十分相近,第一个参赛指定函数的 this 环境,后面的参赛指定函数需要的参数,最大的区别是 bind 不是执行 fun 而是返回一个函数,我们看看如何来用它们显式绑定 this。

var obj1 = { a: 1 }
var obj2 = { a: 11 }
var foo = function () {
  console.log(this.a)
}
a = 'global'
foo.apply(obj1)     // 1
foo.call(obj2)      // 11
foo.bind(global)()  // global

实际情况 bind 更适合用来固定 this 环境。

var obj1 = { a: 1 }
var obj2 = { a: 11 }
var foo = function () {
  console.log(this.a)
}.bind(obj1)
foo.apply(obj2)     // 1
foo.call(obj2)      // 1

另外我们还可以使用 new=> 尖头函数。

new 关键字把 this 指向实例,这个过程发生了什么,我们会在后面章节讨论。

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

而尖头函数十分特别,你可以把它理解为 bind 函数的语法糖,它的 this 同外层函数的 this。

var obj = {
  a: 1,
  foo: function () {
    console.log(this) 
    setTimeout(() => {
      console.log(this) 
    })
  }
}
obj.foo() // obj { a: 1, foo: ƒ }, obj { a: 1, foo: ƒ }

总结

this 是 JavaScript 的一大难点,多年经验的前端程序员都可能对这方面模糊。this 在大量的函数、类库中都有使用,理清显式绑定和隐式绑定有助于理解或书写这类函数。


作者:肖沐宸,github


感谢支持!

赞赏支持
提交评论
评论信息 (请文明评论)
暂无评论,快来快来写想法...
推荐
最大公因数,也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。a,b的最大公约数记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最大公约数也有同样的记号。求最大公约数有多种方法,常见的有质因数分解法、短除法、辗转相除法、更相减损法。与最大公约数相对应的概念是最小公倍数,a,b的最小公倍数记为[a,b]。
web网站上总会有在文本域中提交代码的操作,那么如何处理呢?
java 对象中有很多引用,甚至会出现循环引用,比如 user 对象中有 school 对象,school 对象中又有 user 对象,这样在对 user 对象序列化的时候,就会出现死循环,导致内存溢出。通过一定的方式,将每个对象增加ID 和 REF 引用标识最终可以解决这个问题
项目中需要使用treegrid,找了下easyui 和 ext都有,但是项目用的框架是 byyui,如果为了treegrid 就把这些都加载的话,感觉不太合算。找了大家常用的基于jquery的treegrid.
本文概括了递归、闭包、原型、继承,理清这些基本的概念,有助于你接纳更多的东西,我们会在下一个章节对函数进行更深入的讨论。
开发的项目中有使用到微信开发,由于之前偶尔才用一次,也是用的别人的地址和测试号,这里记录下自己的操作。防止后续遗忘。
最近一直在想着抓一些网盘数据,进行资料归拢,可是当我真正开始的时候.. 还是遇到了反爬,当然我本身就有心理预期,这是肯定会碰到的,只是没想到会在代理IP上耗费这么久,之前的时候也处理过代理IP ,可是由于一知半解,导致很多配置都不理解,debug全靠猜...
关于jquery,他的核心特点就是无new构造和链式调用,这里根据网上的资料,自己简单理解下,有助于消化核心代码。