zoukankan      html  css  js  c++  java
  • js改变this指向

    js中修改this的指向

    方法整理

    call,apply,bind

    以上的三哥方法都是用来改变js中this的指向

    • call
      使用方法:fun.call(thisArg[,arg1[, arg2[, ...]]])
      该方法传递一个thisArgs和一个参数列表,thisArgs制定了函数在运行中的调用者,也就是函数中的this对象,而参数列表会被传入调用函数中。
      call 方法可以在一个对象上借用另一个对象的方法
      案例:Object.prototype.tostring.call([])。一个Array对象借用了Object对象上的方法
      thisArgs的取值情况:
      (1) 不传,或者穿null,undefined,函数中的this指向window对象。
      (2)传递另一个函数的函数名,函数中的this指向这个函数的引用
      (3)传递字符串,数值或者不二类型的那个基础数据类型,函数中的this指向其对应的包装对象,如string,number,boolean
      (4)传递一个对象,函数中的this指向这个对象。
    function a (){
    console.log(this)
    //输出函数a中的this对象
    }
    function b(){
    }//定义函数b  
    var obj = {name:“onepixel”};//定义对象obj
    a.call(); //window
     a.call(null); //window
     a.call(undefined);//window
     a.call(1); //Number
     a.call(''); //String
     a.call(true); //Boolean
     a.call(b);// function b(){}
     a.call(obj); //Object
    

    这是call的核心功能,它允许你在一个对象上调用该对象没有定义的方法,并且这个方法可以访问该对象中的属性

    var a = {
        name:'onepixel', //定义a的属性
        say:function(){ //定义a的方法
            console.log("Hi,I'm function a!");
        }
    };
    function b(name){
        console.log("Post params: "+ name);
        console.log("I'm "+ this.name);
        this.say();
    }
    b.call(a,'test');     //将b的this指向a,参数是b的
    

    还可以通过call方法来调用匿名函数

    在下例中的for循环体内,我们创建了一个匿名函数,然后通过调用该函数的call方法,将每个数组元素作为指定的this值执行了那个匿名函数。这个匿名函数的主要目的是给每个数组元素对象添加一个print方法,这个print方法可以打印出各元素在数组中的正确索引号。当然,这里不是必须得让数组元素作为this值传入那个匿名函数(普通参数就可以),目的是为了演示call的用法。

    var animals = [
      {species: 'Lion', name: 'King'},
      {species: 'Whale', name: 'Fail'}
    ];
    
    for (var i = 0; i < animals.length; i++) {
      (function (i) { 
        this.print = function () { 
          console.log('#' + i  + ' ' + this.species + ': ' + this.name); 
        } 
        this.print();
      }).call(animals[i], i);
    }
    //#0 Lion: King
    //#1 Whale: Fail
    

    apply()方法

    fun.apply(thisArg[, argsArray])
    

    apply和call的唯一区别是第二个参数的传递方式不同,apply的第二个参数必须是一个数组,而call允许传递一个参数列表。值得你注意的是,虽然apply接收的是一个参数数组,但在传递给调用函数时,却是以参数列表的形式传递。
    注意:这里的argsArray可以是一个数组或者类数组对象,如果该参数的值为null 或 undefined,则表示不需要传入任何参数。

    function b(x,y,z){
        console.log(x,y,z);
    }
    b.apply(null,[1,2,3]); // 1 2 3
    
    

    apply方法的实用写法

    //里面有最大最小数字值的一个数组对象
    var numbers = [5, 6, 2, 3, 7];
    
    /* 使用 Math.min/Math.max 在 apply 中应用 */
    var max = Math.max.apply(null, numbers);
    // 一般情况是用 Math.max(5, 6, ..) 或者 Math.max(numbers[0], ...) 来找最大值
    var min = Math.min.apply(null, numbers);
    

    当参数是明确知道数量时用call;不确定的时候用apply,然后把参数push进数组传递进去,也可以通过arguments这个数组来遍历所有的参数。

    bind()方法

    fun.bind(thisArg[, arg1[, arg2[, ...]]])
    
    

    bind是ES5新增的一个方法,它的传参和call类似,但又和call/apply有着显著的不同,即调用call或apply都会自动执行对应的函数,而bind不会执行对应的函数,只是返回了对函数的引用。

    ES5中新增加的bind方法可以弥补call()和apply()方法的不足,由于call/apply会对目标函数自动执行,从而导致它无法在事件绑定函数中使用,因为事件绑定函数不需要我们手动执行,它是在事件被触发时由JS内部自动执行的。而bind在实现改变函数this的同时又不会自动执行目标函数,因此可以完美的解决上述问题,看一个例子就能明白:

    当点击网页时,EventClick被触发执行,输出JSLite.io p1 p2, 说明EventClick中的this被bind改变成了obj对象。如果你将EventClick.bind(obj,'p1','p2') 变成 EventClick.call(obj,'p1','p2') 的话,页面会直接输出 JSLite.io p1 p2

    var obj = {name:'JSLite.io'};
    /**
     * 给document添加click事件监听,并绑定EventClick函数
     * 通过bind方法设置EventClick的this为obj,并传递参数p1,p2
     */
    document.addEventListener('click',EventClick.bind(obj,'p1','p2'),false);
    //当点击网页时触发并执行
    function EventClick(a,b){
        console.log(
                this.name, //JSLite.io
                a, //p1
                b  //p2
        )
    }
    // JSLite.io p1 p2
    
    

    兼容写法

    if (!Function.prototype.bind) {
      Function.prototype.bind = function (oThis) {
        if (typeof this !== "function") {
          // closest thing possible to the ECMAScript 5
          // internal IsCallable function
          throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
        }
    
        var aArgs = Array.prototype.slice.call(arguments, 1), 
            fToBind = this, // this在这里指向的是目标函数
            fNOP = function () {},
            fBound = function () {
              return fToBind.apply(this instanceof fNOP
                     ? this //此时的this就是new出的obj
                     : oThis || this,//如果传递的oThis无效,就将fBound的调用者作为this
                    
                   //将通过bind传递的参数和调用时传递的参数进行合并,并作为最终的参数传递
                   aArgs.concat(Array.prototype.slice.call(arguments)));
            };
        fNOP.prototype = this.prototype;
        //将目标函数的原型对象拷贝到新函数中,因为目标函数有可能被当作构造函数使用
        fBound.prototype = new fNOP();
        //返回fBond的引用,由外部按需调用
        return fBound;
      };
    }
    

    应用

    通过call和apply实现继承:

    function Animal(name,weight){
       this.name = name;
       this.weight = weight;
    }
    function Cat(){
        Animal.call(this,'cat','50');
      //Animal.apply(this,['cat','50']);
       this.say = function(){
          console.log("I am " + this.name+",my weight is " + this.weight);
       }
    }
    var cat = new Cat();
    cat.say();//I am cat,my weight is 50
    
    
  • 相关阅读:
    Tomcat8 配置Oracle11g数据源
    通过代码设置 为横屏
    HttpClient4.3.6 实现https访问
    创建mysql数据库
    设置android状态栏颜色和toolbar颜色一致
    定义任务打印gradle下载的jar包位置
    修改weblogic jvm启动参数
    android.support.v7.widget.Toolbar 中menu图标不显示问题
    android.support.design.widget.AppBarLayout 在android5.0+底部显示空白条问题
    浅析jQuery框架与构造对象
  • 原文地址:https://www.cnblogs.com/wangjiahui/p/10901795.html
Copyright © 2011-2022 走看看