js的this理解以及call apply bind改变this指向

关于JavaScript中的this

1. 函数预编译过程this - > window

function foo() {
    
    
    console.log(this);
}

foo(); //全局变量

函数调用中的this也指向全局变量。

注:ECMAScript5的strict模式不存在全局变量,这里的this是undefined。

2. 全局作用域里this -> window

console.log(this); //全局变量

全局范围使用this指向的是全局变量,浏览器环境下就是window。

注:ECMAScript5的strict模式不存在全局变量,这里的this是undefined。

3. 对象方法调用

var test = {
    
    
    foo: function () {
    
    
        console.log(this);
    }
}

test.foo(); //test对象

对象方法调用中,this指向调用者。

4. 构造函数调用

如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。使用new来调用函数, 或者说发生构造函数调用时,会自动执行下面的操作。

  1. 在函数体最前面隐式的创建一个var this=Object.create(foo.prototype)的空对象
  2. 执行this.xx= xx;往this里面增加属性方法
  3. 隐式的返回this
 function foo(x){
    
    
  this.x = x;
  console.log(this); // foo {x: 2}
}
var f = new foo(2); 
console.log(f.x); // 2

使用new来调用foo()时, 会构造一个新对象并把它绑定到foo()调用中的this上。即构造函数的this指向它实例化出来的对象。

5. call apply bind改变的this

function foo(a, b) {
    
    
    console.log(this);
}

var bar = {
    
    };

foo.apply(bar, [1, 2]); //bar
foo.call(1, 2); //Number对象

使用Function.prototype的call或者apply方法是,函数内部this会被设置为传入的第一个参数。call与apply后面如果是undefined和null,this指向的是window

6. 元素绑定事件,事件触发后 执行的函数中的this 指向的是当前的元素

 <input type="button" value="点我">
 <script>
 document.querySelector("input").onclick = function(){
    
    
 console.log(this); //指向当前按钮
 };
 </script>

改变this指向

在ECMAScript中,每个函数都包含两个继承而来的方法:apply() 和 call(),这两个方法的用途都是在特定的作用域中调用函数,主要作用跟bind一样,用来改变函数体内this的指向,或者说是在函数调用时改变上下文。

1. call和apply

apply() 和 call(), 这两个方法的用途都是在特定的作用域中调用函数,主要作用跟 bind 一样,用来改变函数体内 this 的指向,或者说是在函数调用时改变上下文。

我们可以运用这个特性实现借用别的函数实现自己的功能如下代码:

   function Person(name, age, sex) {
    
    
        this. name = name;
        this.age = age;
        this.sex = sex;
    }
    function Student ( name, age, sex, tel, grade) {
    
    
     // Person.call(this,name, age ,sex) ;
        Person.apply(this,[name, age ,sex]) ;
        this.tel = tel;
        this.grade = grade;
    }
    var student = new Student( 'sunny', 123, 'male', 139, 2017)
    console.log(student.name)//sunny

我们可以看出来,原本Student构造函数中是没有name属性的,我们call和apply都是为了动态改变 this 而出现的,

再来个常见的使用例子:数组没有max方法,可以使用Math对象上的max方法

    const arr =[1,2,3,4,5]
    const max = Math.max.apply(null,arr)
    console.log(max)//5

call

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

fun.call(thisArg,arg1,arg,…)

  • thisArg是fun函数运行时指定的this值(在非严格模式下,指定为null或undefined时会自动指向全局对象)
  • arg1.arg2…是指定的参数列表

apply

fun.apply(thisArg,[argsArray])

  • thisArg是fun函数运行时指定的this值(在非严格模式下,指定为null或undefined时会自动指向全局对象)
  • argsArray是一个数组或类数组对象, 数组中的元素将作为单独的参数传给fun函数如果
  • argsArray为nul或undefined时表示不需要传入任何参数。

2. bind

fun.bind(thisArg,arg1,arg2,…).

  • thisArg当绑定函数被调用时,该参数会作为原函数运行时的this指向。当使用new操作符调用绑定函数时,该参数无效。
  • arg1, arg2, …当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。//如果你某个函数绑定新的this指向并且固定先传入几个变量可以在绑定的时候就传入,之后.调用新函数传入的参数都会排在之后
const obj= {
    
    }
function test(..args) {
    
    
console.log(args);
const newFn = test.bind(obj, 1,2);
newFn(3,4);
// [1,2,3,4]

3. call apply bind总结

直接看看三者之间的关系吧

//先来一个对象big吧
var big = {
    
    
    name:'BaBa',
    saying:function (age){
    
    
        console.log(this.name,'age:',age);
    }
};

//再来一个small对象
var small= {
    
    
    name:'ErZi'
};

//如果想调用big的saying方法来说出‘Erzi’:
//使用bind方法
big.saying.bind(small)(20);//打印结果为ErZi age: 20
//使用call方法
big.saying.call(small,20);//打印结果为ErZi age: 20
//使用apply方法
big.saying.apply(small,[20]);//打印结果为ErZi age: 20

总结三者

1. 使用场景

  • 当一个函数需要改变this指向时且参数较少时可以使用call
  • 如果参数较多,可以将参数整理到一个数组,使用apply
  • 如果想生成一个新函数长期绑定某个对象时,可以使用bind

2. 相同点
都是用来改变this指向

3. 不同点

  • call和apply的用法机乎相同,唯一不同就是参数不同。 call职能一 个个参数传入, apply参
    数是一个数组。
  • bind的传参方式和call相同,但是改变调用函数的指向并返回一个新的函数,之后再调用这个
    函数时候this就指向bind绑定的第一个参数

拓展:自己封装bind方法

//bind方法
    //1、bind方法放在函数的原型中
    //  -->fn.__proto__===fn的构造函数.prototype
    //  -->所有的函数对象的构造函数是Function
    //      -->Function 创建了Function
    //      -->Function 创建了Object 
    //      -->Function 创建了fn
    Function.prototype._bind=function(target){
    
    
        //这里的this其实fn

        //target表示新函数的内部的this的值
        
        //利用闭包创建一个内部函数,返回那个所谓的新函数
        return ()=>{
    
    
            //执行fn里面的逻辑
            this.call(target);  //this.apply(target)
        }

        // //等价于:
        // var _that=this;
        // return function(){
    
    
        //     _that.call(target);
        // }
    }

    function fn(){
    
    
        console.log(this);
    }

    var _f1=fn.bind({
    
    age:18})

猜你喜欢

转载自blog.csdn.net/pz1021/article/details/105144236