JavaScript设计模式-this/call/apply
this
众所周知在 JavaScript 中的 this 的指向是基于函数执行的环境动态绑定的,而并非是声明时的环境。
this 指向
在除去不常用的with和eval具体到实际应用中,this的指向可以分为以下四种:
- 作为对象的方法调用
- 作为普通函数调用
- 构造器调用
- Function.prototype.call 和 Function.prototype.apply 调用 作为对象的方法调用
作为对象的方法调用 this 指向该对象
作为普通函数调用
当函数不作为对象的属性调用时,也就是常说的普通函数方式,此时的 this 总是指向全局对象,在浏览器中是 window 对象(ES6 模块会默认启用严格模式,在严格模式下的 this 指向是未定义并不会指向 window)
构造器调用
JavaScript 中没有类,但是可以从构造器中创建对象,同时也提供了new运算符,是的构造器看起来像一个类,通常情况下,构造器里面的 this 就只想返回的这个对象。(ES6 中的 class 中所有 this 都指向 class 本身)
丢失的 this
这是一个经常遇到的问题, 看下面的代码
1 | const obj = { |
当调用 obj.getName 时,getName 是作为 obj 对象的属性被调用的,所以 this 指向 obj,当另一个变量 getName2 来引用 obj.getName,并调用 getName2 时,此时是作为普通函数调用方式,它的 this 指向全局 window。
call 和 apply
ES3 中给 Function 的原型定义了两个方法,Function.ptototype.call和Function.pototype.apply,这两个方法的应用也非常广泛。
call 和 apply 的区别
call和apply都是非常常用的方法,他们的作用是一样的,区别仅在于传输参数形式不同。
apply接受两个参数第一个参数执行了函数体内this对象的指向,第二个参数作为一个带入下标的集合,这个集合可以为数组,也可以为类数组,apply方法把这个集合中的元素作为参数传递给被调用的函数。
当调用一个函数时,JavaScript 解释器并不会计较形参和实参的数量,类型,以及顺序上的区别,JavaScript 的参数实在内部就用一个数组来表示,从这个意义上来说,apply比call使用率更高,我们不必关心具体有多少参数被传入函数,只要用apply一股脑推过去就好了
call是包装在apply上面的一个语法糖,如果我们明确的知道了函数接受多少个参数,而且想一木了然的表达形参和实参,那么也可以使用call来传递参数
这里说一下bind,bind()方法创建一个新的函数,当被调用时,将其 this 关键字设置为提供的值,在调用新函数时候,在任何提供之前提供一个给定的参数序列。(在 react 中如果在 render 之后使用bind方法绑定 this 的话每次刷新都会创建一个新的函数所以请注意)
call 和 apply 的用途
改变 this 指向
call和apply最常见用于改变函数内部this指向
1 | const obj1 = { |
现在大部分浏览器都实现了Function.prototype.bind 用来指定函数内部的this指向下面模拟一下
1 | Function.prototype.bind = function(context) { |
借用其他对象的方法
借用方法的第一种场景是借用构造函数,通过这种技术,可以实现一些类似继承的效果
1 | const A = function(name) { |