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方法,实现了给对象增加元素。

    谢谢看官。

  • 相关阅读:
    某个牛人做WINDOWS系统文件详解
    常用ASP脚本程序集锦
    LINUX基础:文件安全与权限
    proftpd+mysql+quota
    apache2.0.49tomcat5.0.19jk2建立virtualHost
    URL Redirection(转) Anny
    顶级域名后缀列表(转) Anny
    \u4E00\u9FA5意义 Anny
    How to POST Form Data Using Ruby(转) Anny
    How to get rid of 'Enter password to unlock your login keyring' in Ubuntu(转) Anny
  • 原文地址:https://www.cnblogs.com/jsydb/p/12513179.html
Copyright © 2011-2022 走看看