JS-08函数的4中调用方式详解

目录

1 函数调用方式

 2 方法调用方式

例1:声明一个对象,调用对象原型里的方法

例2:直接调用对象里的方法

例3:声明一个值为函数的变量clear,在一个对象tom里的某个属性c赋值为该变量clear,然后通过该对象tom调用这个变量c

3 构造函数调用方式

例1:有一个函数,用new 来赋值,则是赋值的构造函数

例2:函数里面返回构造函数,可以访问实例本身属性,也可访问实例构造方法prototype中的属性

例3:修改函数的默认原型,指向新原型

4 上下文调用方式

例1:上下文调用call

例2:call和apply异同

例3 :上下文调用bind

5  思考如何解决bind的浏览器兼容性问题


在`ES6之前`,函数内部的this是由该函数的调用方式决定的

函数内部的this跟大小写、书写位置无关

1 函数调用方式

函数内部的this指向window


 
  var age=18;
    var p={
        age:15,
        say:function(){
            console.log(this.age);
        }
    }
    var f1=p.say;   //f1是函数
    f1();   //函数调用-->this:window -->this.age=18

将一个对象的方法赋值给一个变量,则这个变量是一个函数

f1()调用该函数,结果为18,表明函数内部的this指向window

 2 方法调用方式

函数内部的this指向调用该方法的对象


例1:声明一个对象,调用对象原型里的方法

    function Person(){
        this.age=20;
    }
    Person.prototype.run=function(){
        console.log(this.age);
    }
    
    var p1=new Person();
    p1.run();       //打印结果:20

例2:直接调用对象里的方法

   var p2={
        height:180,
        travel:function(){
            console.log(this.height);
        }
    }
    p2.travel()     //打印结果:180

例3:声明一个值为函数的变量clear,在一个对象tom里的某个属性c赋值为该变量clear,然后通过该对象tom调用这个变量c

    var clear=function(){
        console.log(this.length);
    }
    
    var length=50;
    var tom={ c:clear,length:100 };
    tom.c();        //这里是方法调用的方式        

打印this.length 是50 还是100?
-->相当于问:this是指向window还是指向tom呢? 
-->结果为:100  
-->this:tom

结论:由于clear函数被当成tom.c()这种方法的形式来进行调用,所以函数内部的this指向调用该方法的对象:tom 

3 构造函数调用方式

通过new关键字来调用的,那么这种方式就是构造函数的构造函数的调用方式,那么函数内部的this就是该构造函数的实例 


例1:有一个函数,用new 来赋值,则是赋值的构造函数

     function fn(name){
        this.name=name;
      }
 
     var _n=new fn("小明");  //_n有个name属性,值为:小明

例2:函数里面返回构造函数,可以访问实例本身属性,也可访问实例构造方法prototype中的属性

    function jQuery(){
        var _init=jQuery.prototype.init;
        //_init就是一个构造函数
        return new _init();
    }
    jQuery.prototype={
        constructor:jQuery,
        length:100,
        init:function(){
            //this可以访问到实例本身的属性,也可以访问到init.prototype中的属性
            //这里的init.prototype并不是jQuery.prototype
            console.log(this.length);   
            //正确答案:undefined
            //100? 错误的
        }
    }

补充说明:

1.变量声明了未赋值是undefined

2.属性不存在也是undefined


例3:修改函数的默认原型,指向新原型

对象的属性查找规则

1、首先查看本身有没有length属性
2、如果本身没有该属性,那么去它的原型对象中查找
3、如果原型对象中没有,那么就去原型对象的原型对象中查找,最终一直找到根对象(Object.prototype)
4、最终都没有找到的话,我们认为该对象并没有该属性,如果获取该属性的值:undefined

    function jQuery(){
        var _init=jQuery.prototype.init;
        //_init就是一个构造函数
        return new _init();
    }
    jQuery.prototype={
        constructor:jQuery,
        length:100,
        init:function(){
            //this指向init构造函数的实例
 
            console.log(this.length);   //100   
        }
    }
    var $init=jQuery.prototype.init;
    //修改了init函数的默认原型,指向新原型
    $init.prototype=jQuery.prototype;

    jQuery();//打印出:100

4 上下文调用方式

上下文调用方式,有3种,call、apply、bind

  1.call和apply是立刻执行这个函数,并且在执行过程中绑定了this这个值

  2.bind并没有立即执行这个函数,而是创建了一个新函数,新函数绑定了this这个值


例1:上下文调用call

    function f1(){
        console.log(this);
    }
    //call方法的第一个参数决定了函数内部的this的值
    f1.call([1,3,5])
    f1.call({age:20,height:1000})
    f1.call(1)      
    f1.call("abc")
    f1.call(true);
    f1.call(null)
    f1.call(undefined);

    上述代码可以用apply完全替换

    总结:

    call方法的第一个参数:

    1、如果是一个对象类型,那么函数内部的this指向该对象

    2、如果是undefined、null,那么函数内部的this指向window

    3、如果是数字-->this:对应的Number构造函数的实例。如果输入1 输出 new Number(1)

     如果是字符串-->this:String构造函数的实例。如果输入 "abc"   --> new String("abc")

     如果是布尔值-->this:Boolean构造函数的实例。如果输入false   --> new Boolean(false)


例2:call和apply异同

   同:call和apply都可以改变函数内部的this的值

   异:传参的形式不同

    function toString(a,b,c){
        console.log(a+" "+b+" "+c);
    }
    toString.call(null,1,3,5)   //"1 3 5"
    toString.apply(null,[1,3,5])//"1 3 5"

例3 :上下文调用bind

1)   调用了setTimeout函数,它会在指定的延迟(这里是50毫秒)后执行提供的函数。但是,请注意,在JavaScript中,setTimeout的回调函数中的this并不指向调用setTimeout的对象(这里是obj),而是指向全局对象(在浏览器中通常是window

    var obj = {
        age: 18,
        run: function () {
            console.log(this);  //this:obj

            var _that = this;

            setTimeout(function () {
                //this指向window
                console.log(this.age);//undefined
                console.log(_that.age);//18
            }, 50);
        }
    }

    obj.run();


2)通过执行了bind方法,匿名函数本身并没有执行,只是改变了该函数内部的this的值,指向obj5

    var obj5 = {
        age: 18,
        run: function () {
            console.log(this);  //this:obj5

            setTimeout((function () {
                console.log(this.age);  //18
            }).bind(this), 50);  //this:obj5
        }
    }
    obj5.run();

3)bind基本用法

   执行了bind方法之后,产生了一个新函数,这个新函数里面的逻辑和原来还是一样的,唯一的不同是this指向{ seconds:100 }

    function speed(){
        console.log(this.seconds);
    }
    var speedBind = speed.bind({ seconds:100 });
    speedBind();    //100

   匿名函数.调用bind方法执行

   xxx.bind()()   一般采用这种方法


    (function eat(){
        console.log(this.seconds);
    }).bind({ seconds:360 })()  //360

4)

   var obj={
        name:"西瓜",
        drink:(function(){
            //this指向了:{ name:"橙汁" }
            console.log(this.name);
        }).bind({ name:"橙汁" })
    }
    obj.drink();    //"橙汁"

    var p10={
        height:88,
        run:function(){
            //this
            setInterval((function(){
                console.log(this.height);   //88
            }).bind(this),100)
        }
    }
    p10.run();

5  思考如何解决bind的浏览器兼容性问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摸爬打滚的小M

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值