JavaScript中的this/call/apply/bind

2020-3-1    前端达人

文章目录

一、this

1.什么是this

2.this 代表什么

3.绑定 this 的方法

4.this的指向

5.改变指向

二、Function.prototype.bind()

三、call/apply

1.定义

2.语法

3.异同

一、this

1.什么是this

this 关键字在大部分语言中都是一个重要的存在,JS中自然不例外,其表达的意义丰富多样甚至有些复杂,深刻理解this是学习JS、面向对象编程非常重要的一环。



2.this 代表什么

this代表函数(方法)执行的上下文环境(上下文,类似与你要了解一篇文章,了解文章的上下文你才能清晰的了解各种关系)。



但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。



1.在方法中,this 表示该方法所属的对象。



2.如果单独使用,this 表示全局对象。



3.在函数中,this 表示全局对象。



4.在函数中,在严格模式下,this 是未定义的(undefined)。



5.在事件中,this 表示接收事件的元素。



6.类似 call() 和 apply() 方法可以将 this 引用到任何对象。



3.绑定 this 的方法

this的动态切换,固然为 JavaScript 创造了巨大的灵活性,但也使得编程变得困难和模糊。有时,需要把this固定下来,避免出现意想不到的情况。JavaScript 提供了call、apply、bind这三个方法,来切换/固定this的指向。



4.this的指向

1.在一般函数方法中使用 this 指代全局对象

function test(){
    this.x = 1;  //这里this就是window
    console.log(this.x);
  }
  test(); // 1



JS规定,函数中的this,在函数被调用时确定,它指函数当前运行的环境。

2.作为对象方法调用,this 指代上级对象

var x =3;
function test(){
  alert(this.x);
}
var o = {
  x:1,
  m:test 
};
o.m(); // 1



如果函数作为对象的方法时,方法中的 this 指向该对象。

3.作为构造函数调用,this 指代new 出的对象

function test(){
    console.log(this);
  }
  var o = new test();
       test();
//可以看出o代表的不是全局对象

new关键词的作用是调用某个函数并拿到其中的返回值,只是调用过程稍特殊。在上面的代码实例中。test函数被new关键词调用时,内部依次执行了以下步骤:

(1)创建一个空对象。

(2)将这个空对象的原型,指向这个构造函数的prototype。

(3)将空对象的值赋给函数内部的this(this就是个空对象了)。

(4)执行函数体代码,为this这个对象绑定键值对。

(5)返回this,将其作为new关键词调用oop函数的返回值。

所以构造函数中的this,依旧是在构造函数被new关键词调用时确定其指向,指向的是当前被实例化的那个对象。

4.箭头函数中的this
箭头函数是ES6的新特性,最重要的特点是它会捕获其所在上下文的this作为自己的this,或者说,箭头函数本身并没有this,它会沿用外部环境的this。也就是说,箭头函数内部与其外部的this是保持一致的。

this.a=20
var test={
    a:40,
    init:()=>{
        console.log(this.a)
        function go(){
            this.a=60
            console.log(this.a)
        }
        go.prototype.a=50
        return go
    }   
}

var p=test.init()
p()
new (test.init())()
//输出 20 60 60 60

5.改变指向
this的动态切换,固然为 JavaScript 创造了巨大的灵活性,但也使得编程变得困难和模糊。有时,需要把this固定下来,避免出现意想不到的情况。JavaScript 提供了call、apply、bind这三个方法,来切换/固定this的指向。

bind方法和apply、call稍有不同,bind方法返回一个新函数,以后调用了才会执行,但apply、call会立即执行。

二、Function.prototype.bind()
bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()中的第一个参数的值,例如:f.bind(obj),实际上可以理解为obj.f(),这时f函数体内的this自然指向的是obj;

示例:
function f(y, z){
    return this.x + y + z;
}
var m = f.bind({x : 1}, 2);
console.log(m(3));
//6
这里bind方法会把它的第一个实参绑定给f函数体内的this,所以这里的this即指向{x : 1}对象,从第二个参数起,会依次传递给原始函数,这里的第二个参数2,即是f函数的y参数,最后调用m(3)的时候,这里的3便是最后一个参数z了,所以执行结果为1 + 2 + 3 = 6分步处理参数的过程其实是一个典型的函数柯里化的过程(Curry)。

三、call/apply
1.定义
每个函数都包含两个非继承而来的方法:call()方法和apply()方法。

call和apply可以用来重新定义函数的执行环境,也就是this的指向;call和apply都是为了改变某个函数运行时的context,即上下文而存在的,换句话说,就是为了改变函数体内部this的指向。

2.语法
call()

调用一个对象的方法,用另一个对象替换当前对象,可以继承另外一个对象的属性,它的语法是:

Function.call(obj[, param1[, param2[, [,...paramN]]]]);
1
obj:这个对象将代替Function类里this对象
params:一串参数列表

说明:call方法可以用来代替另一个对象调用一个方法,call方法可以将一个函数的对象上下文从初始的上下文改变为obj指定的新对象,如果没有提供obj参数,那么Global对象被用于obj。

apply()

和call()方法一样,只是参数列表不同,语法:

Function.apply(obj[, argArray]);

obj:这个对象将代替Function类里this对象
argArray:这个是数组,它将作为参数传给Function

说明:如果argArray不是一个有效数组或不是arguments对象,那么将导致一个TypeError,如果没有提供argArray和obj任何一个参数,那么Global对象将用作obj。

3.异同
相同点

call()和apply()方法的相同点就是这两个方法的作用是一样的。都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。

一般来说,this总是指向调用某个方法的对象,但是使用call()和apply()方法时,就会改变this的指向,看个例子:
function add(a, b) {
    return a + b;
}

function sub(a, b) {
    return a - b;
}

console.log(add.call(sub, 2, 1));//3


分享本文至:

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档