this

一,理解this

定义:this引用的是函数执行的环境变量

1.普通函数中的this

function fn() {
  console.log(this)//this指向顶层,浏览器中是widow,node中是gobal对象
}
let obj = {
    fn: function() {
        console.log(this) //this指向obj对象
    }
}
ARR.prototype.add = function(arr){
    console.log(this) // this指向[1,2,3]。js指向调用此方法的对象
}
[1,2,3].add()

2.构造函数中的this

构造函数中的this指向新创建的对象本身

function person(obj) {
    this.name = obj.name
    console.log(this) //当前new的对象
}
var p1 = new person({name:"bob"})
console.log(p1) //同上

3.ES6箭头函数中的this

指向包裹箭头函数的最外层

var name = "Bob";
var obj = {
    name: "Dancy",
    fn: () => { 
         console.log(this); //顶层对象,在浏览器中是window对象
    }
}
 obj.fn();

二,call apply和bind的理解

三个方法都继承自Function.prototype。所以所有函数皆能调用

参数
  • call:call(this,arg1,arg2,arg3)
  • apply: apply(this,[arg1,arg2,arg3])
  • bind: bind(this,arg1,arg2,arg3)
定义:

call和apply: 指定函数内部的this指向,然后再所指定的作用域中调用该函数,立即执行该函数。

bind: 指定函数内部的this指向,然后返回一个新函数。bind不会立即执行一个函数

相同点:
  • 三者第一个参数都是指定函数的this指向
  • 都可以在函数调用时给函数传递参数
区别:
  • call和apply都会自动调用函数。bind是返回一个新的函数。需要加 ()才能调用
  • call和bind的参数一致。apply只有两个参数,第二个参数是个数组。传参都放在数组中

例子:

let obj ={
    a:23,
    e: 88
}
function fn(a,b,c) {
    console.log(this.a); //obj.a this指向obj
    console.log(a+b+c+this.e);  //
}
fn.call(obj,1,2,3); // 23 94
fn.apply(obj,[1,2,3]) // 23 6
fn.bind(obj,1,2,3)() // 23 6

三,call apply和bind的应用场景

1.返回数组中的最大值
arr = [1,2,3,4]
console.log(Math.max.apply(null,arr)) // 把数组的每一项作为Math.max()的入参
console.log(Math.max.call(...arr))
console.log(Math.max.bind(...arr)())
2.将数组的空元素变为undefined

空元素与undefined的区别在于,数组的forEach方法会跳过空元素,但是不会跳过undefined和null

let a=[1,,3]
a.forEach((item)=>console.log(item)) //1 3 跳过空元素
Array.apply(null,a).forEach((item)=> console.log(item)) // 1 undefined 3
3.将类数组对象arguments转换成数组
function change(a,b,c) {
    let arrarg = [].slice.call(arguments);  //Array.prototype.slice.call(arguments);
    console.log(arrarg);
}
change(1,2,3)

arguments不是数组,但是可以向数组一样循环。而slice方法的底层也是依靠循环实现的,且arr.slice() -> arr。我们只要在slice函数运行的时候把slice的this指向arguments就行。

只有数组才能调用现成slice函数。调用方法有两种

一, Array.prototype.slice() // 通过原型链直接去访问
二,[].slice //来个继承了slice的空数组

4.定时器中使用bind

只是单纯的需要一个指向新的this的函数,就可以用bind。call和apply会立即调用函数

obj={
    index: 0,
    time: 0
}
function fn() {
    this.index ++
    this.time += 100
    console.log(this)
}
setInterval(fn.bind(obj),1000)
5.组合继承
function parent(value) {
    this.val = value
}
parent.prototype.getValue=function(){
    console.log(this.val)
}
function child(value){
    parent.call(this,value)
}
child.prototype = new parent()
let test = new child(1)
test.getValue()