• JavaScript设计模式与开发实践---读书笔记(2) this、call和apply


    this、call和apply

    this的指向:

    this总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

    1.作为对象的方法被调用

    当函数作为对象的方法被调用时,this指向该对象

    2.作为普通函数调用

    此时的this总是指向全局对象。在浏览器的JavaScript里,这个全局对象是window对象。

    有时候,我们希望div节点事件函数内部的this指向该div节点,可以用一个变量保存div节点的引用:

    var that = this;

    在ES5的严格模式下,这种情况下的this已被规定为不会指向全局对象,而是undefined

    3.构造器调用

    构造器的外表跟普通函数一模一样,它们的区别在于被调用的方式。当用new运算符调用运算符时,该函数总会返回一个对象,通常情况下,构造器里的this就指向返回的这个对象。

    注意:使用new调用构造器时,还要注意一个问题,如果构造器显式地返回了一个object类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前期待的this。

    4.Function.prototype.call或Function.prototype.apply调用

    用Function.prototype.call或Function.prototype.apply可以动态的改变传入函数的this。

    丢失的this

    call和apply

    Function.prototype.call或Function.prototype.apply都是非常常用的方法。它们的作用一模一样,区别仅在于传入参数形式的不同。

    apply接受两个参数,第一个参数指定了函数体内this对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply方法把这个集合中的元素作为参数传递给被调用的函数:

    var func = function(a,b,c){
        alert([a,b,c]);  //输出[1,2,3]
    };
    func.apply(null,[1,2,3]);

    call传入的参数数量不固定,跟apply相同的是,第一个参数也是代表函数体内的this指向,从第二个参数开始往后,每个参数被依次传入参数:

    var func = function(a,b,c){
        alert([a,b,c]);  //输出[1,2,3]
    };
    func.call(null,1,2,3);

    JavaScript的参数在内部就是用一个数组来表示的。从这个意义上来说,apply比call的使用率更高,我们不必关心具体有多少参数被传入参数,只有用apply一股脑地推过去就可以了。

    call是包装在apply上面的一颗语法糖,明确知道函数接受多少个参数,也可以用call来传送参数。

    当使用call或者apply的时候,如果我们传入的第一个参数为null,函数体内的this会指向默认的宿主对象,在浏览器中则是window,

    但如果是在严格模式下,函数体内的this还是为null。

    call和apply的用途:

    1.改变this的指向

    最常见的用途是改变函数内部的this指向。

    2.Function.prototype.bind

    Function.prototype.bind,用来指定函数内的this指向

    模拟bind实现:

    Function.prototype.bind = function(context){
        var self = this;//保存原函数
        return function(){//返回一个新的函数
            return self.apply(context,arguments);//执行新的函数的时候,会把之前传入的context当作新函数体内的this
        }
    };
    
    var obj = {
        name:'sven'
    };
    
    var func = function(){
        alert(this.name);//输出:sven
    }.bind(obj);
    
    func();

    复杂版:

    Function。prototype.bind = function(){
        var self = this,//保存原函数
              context = [].shift.call(arguements),//需要绑定的上下文
              args = [].slice.call(arguements);//剩余的参数转成数组
        return function(){
           return self.apply(context,[].concat.call(args,[].slice.call(arguements))); 
        //执行新的函数的时候,会把之前传入的context当作新函数体内的this
        //并且组合两次分别传入的参数,作为新函数的参数
        }
    };
    
    var obj = {
        name:'sven'
    };
    
    var func= function(a,b,c,d){
        alert(this.name);//输出:sven
        alert([a,b,c,d]);//输出:[1,2,3,4]
    }.bind(obj,1,2);
    
    func(3,4);

    3.借用其他对象的方法
    借用方法的第一种场景是"借用构造函数",通过这种技术,可以实现一些类似继承的效果。

    借用方法的第二种运用场景跟我们的关系更加密切。

    函数的参数列表arguments是一个类数组对象,虽然它也有"下标",但它并非真正的数组,所以不能像数组一样,进行排序操作或者往集合里添加一个新的元素。这种情况下,我们常常会借用Array.prototype对象上的方法。如Array.prototype.push,Array.prototype.slice,Array.prototype.shift等。

  • 相关阅读:
    几种常用的认证机制
    几种任务调度的 Java 实现方法与比较
    vue 安装教程
    JDK版本导致Unsupported major.minor version 52.0 error
    在SpringMVC框架下实现文件的 上传和 下载
    SpringMVC框架下实现JSON(类方法中回传数据到jsp页面,使用jQuery方法回传)
    SpringMVC框架下数据的增删改查,数据类型转换,数据格式化,数据校验,错误输入的消息回显
    SpringMVC框架的基础知识;
    hibernate的二级缓存
    hibernate检索方式(HQL 检索方式,QBC 检索方式,本地 SQL 检索方式)
  • 原文地址:https://www.cnblogs.com/6489c/p/5933137.html
Copyright © 2020-2023  润新知