JS基础总结(4)——this指向及call/apply/bind

前言

农历2019即将过去,趁着年前几天上班事情少,整理了一下javascript的基础知识,在此给你们作下分享,喜欢的大佬们能够给个小赞。本文在github也作了收录。javascript

本人github: github.com/Michael-lzg前端

this 指向

使用 JavaScript 开发的时候,不少开发者多多少少会被 this 的指向搞蒙圈,可是实际上,关于 this 的指向,记住最核心的一句话:哪一个对象调用函数,函数里面的 this 指向哪一个对象。vue

一、普通函数:谁调用指向谁

全局变量指向全局对象-windowjava

var username = 'cn'
function fn() {
  alert(this.username) //cn
}
fu()
复制代码

有一点须要注意,let 声明的全局变量,不是指向 window 对象webpack

let username = 'cn'
function fn() {
  alert(this.username) //undefined
}
fn()
复制代码

二、对象函数调用

就是那个函数调用,this 指向哪里git

window.b = 2222
let obj = {
  a: 111,
  fn: function() {
    alert(this.a) //111
    alert(this.b) //undefined
  }
}
obj.fn()
复制代码

3.构造函数中调用

JS里的普通函数可使用new操做符来建立一个对象,此时该函数就是一个构造函数,箭头函数不能做为构造函数。执行new操做符,其实JS内部完成了如下事情:github

  1. 建立一个空的简单JavaScript对象(即{});
  2. 将构造函数的prototype绑定为新对象的原型对象 ;
  3. 将步骤1新建立的对象做为this的上下文并执行函数 ;
  4. 若是该函数没有返回对象,则返回this。
function A () {
  this.a = 1
  this.func = () => {
    return this
  }
}

let obj = new A()
console.log(obj.a) // 1
console.log(obj.func() === obj) // true
复制代码

4.箭头函数中调用

箭头函数的this指向,和箭头函数定义所在上下文的this相同。对于普通函数,this在函数调用时才肯定;而对于箭头函数,this在箭头函数定义时就已经肯定了,而且不能再被修改。web

let obj = {
  A () {
    return () => {
      return this
    }
  },
  B () {
    return function () {
      return this
    }
  }
}

let func = obj.A()
console.log(func() === obj) // true

func = obj.B()
console.log(func() === obj) // false
console.log(func() === window) // true
复制代码

apply、call、bind

在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。 举个例子算法

function fruits() {}

fruits.prototype = {
  color: 'red',
  say: function() {
    console.log('My color is ' + this.color)
  }
}

var apple = new fruits()
apple.say() //My color is red

// 可是若是咱们有一个对象banana= {color : "yellow"} ,咱们不想对它从新定义 say 方法,
//那么咱们能够经过 call 或 apply 用 apple 的 say 方法:
banana = {
  color: 'yellow'
}
apple.say.call(banana) //My color is yellow
apple.say.apply(banana) //My color is yellow
复制代码

apply、call 区别

对于 apply、call 两者而言,做用彻底同样,只是接受参数的方式不太同样vue-cli

func.call(this, arg1, arg2)
func.apply(this, [arg1, arg2])
复制代码

apply、call 实例

// 数组追加
var array1 = [12 , "foo" , {name:"Joe"} , -2458];
var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
// array1 值为 [12 , "foo" , {name:"Joe"} , -2458 , "Doe" , 555 , 100]

// 获取数组中的最大值和最小值
var  numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers),   //458
var maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

// 验证是不是数组
functionisArray(obj){
  return Object.prototype.toString.call(obj) === '[object Array]'
}
复制代码

bind()

bind()最简单的用法是建立一个函数,使这个函数不论怎么调用都有一样的 this 值。 bind()方法会建立一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以建立它时传入 bind()方法的第一个参数做为 this,传入 bind() 方法的第二个以及之后的参数加上绑定函数运行时自己的参数按照顺序做为原函数的参数来调用原函数。

this.num = 9
var mymodule = {
  num: 81,
  getNum: function() {
    console.log(this.num)
  }
}

mymodule.getNum() // 81

var getNum = mymodule.getNum
getNum() // 9, 由于在这个例子中,"this"指向全局对象

var boundGetNum = getNum.bind(mymodule)
boundGetNum() // 81
复制代码

当调用 bind 函数后,bind 函数的第一个参数就是原函数做用域中 this 指向的值

function func() {
  console.log(this)
}

let newFunc = func.bind({ a: 1 })
newFunc() // 打印:{a:1}

let newFunc2 = func.bind([1, 2, 3])
newFunc2() // 打印:[1,2,3]

let newFunc3 = func.bind(1)
newFunc3() // 打印:Number:{1}

let newFunc4 = func.bind(undefined / null)
newFunc4() // 打印:window
复制代码
  • 当传入为 null 或者 undefined 时,在非严格模式下,this 指向为 window。
  • 当传入为简单值时,内部会将简单的值包装成对应类型的对象,数字就调用 Number 方法包装;字符串就调用 String 方法包装;true/false 就调用 Boolean 方法包装。要想取到原始值,能够调用 valueOf 方法。

传递的参数的顺序问题

function func(a, b, c) {
  console.log(a, b, c) // 打印传入的实参
}

let newFunc = func.bind({}, 1, 2)

newFunc(3) //1,2,3
// 能够看到,在 bind 中传递的参数要先传入到原函数中。
复制代码

返回的新函数被当成构造函数

// 原函数
function func(name) {
  console.log(this) // 打印:经过{name:'wy'}
  this.name = name
}
func.prototype.hello = function() {
  console.log(this.name)
}
let obj = { a: 1 }
// 调用bind,返回新函数
let newFunc = func.bind(obj)

// 把新函数做为构造函数,建立实例

let o = new newFunc('seven')

console.log(o.hello()) // 打印:'seven'
console.log(obj) // 打印:{a:1}
复制代码

新函数被当成了构造函数,原函数 func 中的 this 再也不指向传入给 bind 的第一个参数,而是指向用 new 建立的实例。在经过实例 o 找原型上的方法 hello 时,可以找到原函数 func 原型上的方法。

apply、call、bind 比较

  • apply 、call 、bind 三者都是用来改变函数的 this 对象的指向的;
  • apply 、call 、bind 三者第一个参数都是 this 要指向的对象,也就是想指定的上下文;
  • apply 、call 、bind 三者均可以利用后续参数传参;
  • bind 是返回对应函数,便于稍后调用;apply 、call 则是当即调用 。
var obj = {
  x: 81
}

var foo = {
  getX: function() {
    return this.x
  }
}

console.log(foo.getX.bind(obj)()) //81
console.log(foo.getX.call(obj)) //81
console.log(foo.getX.apply(obj)) //81
复制代码

推荐文章

关注的个人公众号不按期分享前端知识,与您一块儿进步!

相关文章
相关标签/搜索