zoukankan      html  css  js  c++  java
  • 浅谈js中的this,call,apply

    什么是this?

    简单点来说JavaScript中的this总是指向一个对象,至于这个对象是什么,就有很多情况了。

    出去with和eval不常用的情况,实际应用中,this的指向大致有这四种分类:

    1.作为对象的方法调用

    var obj = {
        name: 'ydb',
        sayName: function(){
            console.log(this.name);
        }
    }
    obj.sayName();

    2.作为普通函数调用

    var obj = {
        name: 'ydb',
        sayName: function(){
            console.log(this.name);
        }
    }
    var sayName = obj.sayName;
    sayName();

    这里全局的sayName就是一个普通函数,谁调用this就指向谁(在这里浏览器中指向window),输出undefined

    3.构造器调用

    class Perople {
        constructor(name){
            this.name = name;
        }
        sayName(){
            console.log(this.name);
        }
    }
    var person1 = new Perople('ydb');

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

    var obj1 = {
        name: 'ydb',
        sayName: function(){
            console.log(this.name);
        }
    }
    var obj2 = {name: 'ydb2'};
    var obj3 = {name: 'ydb3'};
    obj1.sayName.call(obj2); // ydb2
    obj1.sayName.apply(obj3); // ydb3

    上面就是this常用的四种方法。

    关于this我们总是会遇到this指向不正确的问题,比如:

    var getID = document.getElementById;
    console.log(getID('div1'));

    假如我们有一个id属性为div1的dom元素,我们这样子获取,在有些浏览器引擎中是会抛出异常的,因为这个方法里面内部用到了this,它希望的this是docuemnt这个对象,我们现在把getID执行,就把这个函数作为普通函数调用了,其内部的this已经指向window了,所以会抛出异常。

    我们使用call或者apply来修复这个this,代码如下:

    document.getElementById = (function(func){
        return function() {
            return func.apply(document,arguments);
        }
    })(document.getElementById)
    var getID = document.getElementById;
    console.log(getID('div1'));

    好了,现在我们就修复了this,这里用到了高阶函数,不做额外的扩展。

    既然call,apply很常用我们就来说说他们之间的区别:

    他们都能改变函数执行this的指向,还可以传入额外的参数,但是他们之间的传参是有区别的,看如下代码:

    console.log(Math.max.apply(null,[1,2,3]));
    console.log(Math.max.call(null,1,2,8));
    在这里我们使用内置对象Math的max方法,求最大值,不需要改变this,所以传入null(this指向默认的宿主对象),后面的参数就是这两个方法掺入的额外参数。
    我们看见apply是可以数组方法传参的,call只能一个一个参数列出来传入。
     
    相信你们应该见过还有一个实现this指向改变的方法,就是Function.prototype.bind
    有了apply和call我们可以很简单的实现一个bind,代码如下:
    Function.prototype.bind = function(ctx){
        var _that = this; //保存原函数的引用
        return function() {
           return  _that.apply(ctx,arguments);
        }
    }

    看看是不是很简单。还可以根据自己的需求扩展这个bind方法,但是这里是为了演示,最好不要给js的内置对象的属性做修改,避免出现全局的错误,想要好的实现,可以参考vue源码中对数组变化监听的实现。这里也用到了高阶函数,所以说高阶函数是走向高级程序员的必经之路(虽然我是一个小彩笔)。

    既然有了改变this指向的方法,那我们可以调用其他对象的方法实现很多功能,举一个例子,假如一个对象满足下面两个条件,那么就可以实现这么一个功能。

    1.对象本身要可以存取属性

    2.对象的length属性可读写

    实现的功能如下:

    var obj = {
        length: 0
    }
    Array.prototype.push.call(obj,'a');
    Array.prototype.push.call(obj,'b');
    console.log(obj[0]);
    console.log(obj[1]);
    console.log(obj.length);

    我们知道数组的push方法是增加一个元素,那么我们这里借用数据的push方法,实现了给对象增加元素。

    谢谢看官。

  • 相关阅读:
    Tomcat集群Cluster实现原理剖析[转] 文件同步
    看到一个比较好的jbpm教程,感谢一下
    vi显示行号
    安装apache2参数详解
    Windows平台下查看占用端口的程序
    struts2中使用token避免重复提交
    在window下安装开源的中文界面的项目管理软件Redmine
    Java中数据存储
    求素数算法网摘
    模式工程化实现及扩展读书笔记——设计原则
  • 原文地址:https://www.cnblogs.com/jsydb/p/12513179.html
Copyright © 2011-2022 走看看