this 介绍

this 总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境

this 的指向

  • 作为对象的方法调用:指向该对象

  • 作为普通函数调用:指向全局对象(严格模式下:undefined)

  • 构造器调用: 指向new出来的实例对象

  • Function.prototype.callFunction.prototype.apply 调用:动态绑定的对象

document.getElementById()的内部实现中需要用到 this,并且这个 this 被期望指向 document

  1. document.getElementById = (
  2. function(func) {
  3. return function() {
  4. return func.apply(document, arguments)
  5. }
  6. }
  7. )(document.getElementById)
  8. var getId = document.getElementById

call && apply

  • 传入的第一个参数为null, 函数体内的 this 会指向默认的宿主对象,在浏览器中则是window.但是在严格模式下,函数体内的 this 还是为 null
  • 有时候使用 call 或 apply 的目的不在于指定 this 指向,而是借用其他对象的方法

Math.max.apply(null, [1,2,3,4,5]) 等同于 Math.max(...[1,2,3,4,5])

改变this的指向

  1. Function.prototype.bind = function() {
  2. var self = this // 保存原函数
  3. var context = [].shift.call(arguments) // 需要绑定的 this 上下文
  4. var args = [].slice.call(arguments) // 剩余的参数转成数组
  5. return function() { // 返回一个新的函数
  6. return self.apply(context, [].concat.call(args, [].slice.call(arguments)))
  7. // 执行新的函数的时候,会把之前传入的context当作新函数体内的this
  8. // 并且组合两次分别传入的参数,作为新函数的参数
  9. }
  10. }
  11. var obj = {
  12. name: 'lulu'
  13. }
  14. var func = function(a, b, c, d) {
  15. alert(this.name)
  16. alert([a, b, c, d])
  17. }.bind(obj, 1, 2)
  18. func(3, 4)

借用其他对象的方法

  1. 借用构造函数

从而实现一些类似继承的效果

  1. var A = function(name){
  2. this.name = name
  3. }
  4. var B = function() {
  5. A.apply(this, arguments)
  6. }
  7. B.prototype.getName = function(name) {
  8. return this.name
  9. }
  10. var b = new B('lulu')
  11. console.log(b.getName()) // lulu
  1. 操作arguments对象时借用Array.prototype上的方法

  • 向 arguments 中添加一个新的元素:Array.prototype.push.call(arguments, …)

  • 把 arguments 转换成一个真的数组:Array.prototype.slice.call(arguments)

  • 截去 arguments 的头一个元素:Array.prototype.shift.call(arguments)

  1. (function() {
  2. Array.prototype.push.call(arguments, 3)
  3. console.log(arguments) // [1,2,3]
  4. })(1,2)
  1. // V8 源码实现上面的代码
  2. function ArrayPush () {
  3. var n = TO_UINT32(this.length) // 被 push 的对象的 length
  4. var m = %_ArgumentsLength() // push 的参数个数
  5. for (var i = 0; i < m; i++) {
  6. this[n + i] = %_Arguments[i] // 对象本身要可以存取属性
  7. }
  8. this.length = n + m // 修正 length 属性的值
  9. return this.length // 对象的 length 属性要可读写
  10. }