• JavaScript OOP(二):this关键字以及call、apply、bind


    JavaScript的this关键字非常灵活!

    this 返回的总是对象;即返回属性或方法“当前”所在的对象
     1 var o1={
     2     name:'apple',
     3     age:100,
     4     msg:function(){
     5         return '显示name和age信息:'+'name: '+this.name+', age: '+this.age;
     6     }
     7 };
     8 //针对msg中的this进行研究:
     9 console.log(o1.msg());//this 指向当前对象o1
    10 var o2={
    11     name:'blue',
    12     age:1000
    13 };
    14 o2.msg=o1.msg;
    15 console.log(o2.msg());//this 指向当前对象o2

    当o1.msg()时,this指向o1;而o2.msg()时,this指向o2。也就是this指向的是“当前”环境运行时所在的对象。

    运行结果:

    将函数提出来,更形象的表示:

     1 console.log('---');
     2 function f(){
     3     console.log(this.name1);
     4 }
     5 var o3={
     6     name1:'alice',
     7     info:f
     8 };
     9 var o4={
    10     name1:'boy',
    11     info:f
    12 };
    13 f();//undefined
    14 o3.info();//alice
    15 o4.info();//boy

    f():this指向顶层对象window;o3.info():this指向的是o3;o4.info():this指向的是o4。即this总是指向“当前”运行时所在的对象。

    运行结果:

    如果我们在全局环境中,将对象中的方法赋值给变量。以本文最上面代码o1.msg示例:

    1 var name='abc';
    2 var age=1;
    3 var test1=o1.msg;
    4 console.log(test1());//此时this指向顶层对象window

    此时test1():this指向的是window

    运行结果:

    由上面的这些例子,我们可以“粗略”的认为每个函数中都存在着this,它总是指向当前运行环境的对象

    全局环境下的this指向顶层对象window

    1 function test2(){
    2     if(this === window){
    3         console.log('此时this 指向顶层对象window');
    4     }
    5 }
    6 test2();

    运行结果:

    构造函数中的this指向实例化的对象
     1 function Test3(num){
     2     this.num=num;
     3 }
     4 var t3=new Test3(100);
     5 console.log(t3.num);//this 指向t3
     6 
     7 Test3.prototype.m=function (){//所有由Test3构造函数生成的实例化对象都共享m方法
     8     return this.num;
     9 };
    10 console.log(t3.m());//this 指向t3

    运行结果:

    注意下面这种情况:

     1 var o5={
     2     name:'application',
     3     send:function(){
     4         console.log(this
     5         );
     6     }
     7 };
     8 o5.send();//o5
     9 (o5.send=o5.send)();//window
    10 /**
    11  * 相当于
    12  * (o5.send=function(){
    13  * console.log(this);
    14  * })
    15  */
    16 (false||o5.send)();//window
    17 /**
    18  * 相当于
    19  * (false || function(){
    20  * console.log(this);
    21  * })
    22  */
    23 (1,o5.send)();//window
    24 /**
    25  * 相当于
    26  * (1,function(){
    27  * console.log(this);
    28  * })
    29  */

    即:除非直接使用o5.send(),结果返回当前对象;否则均返回顶层对象window

    运行结果:

    如果方法位于多层对象的内部,那么this指向当前对象层,不会继承更上面的层:

     1 var o6={
     2     name:'cat',
     3     f:{
     4         f1:function (){
     5             console.log(this.name);
     6             console.log(this==o6.f);//其实this指向的是o6.f
     7         }
     8     }
     9 };
    10 o6.f.f1();//undefined
    11 //因为此时this指向的是f

    上面代码中o6对象中f属性对应的值,是一个对象。该对象里面又存在着一个函数,此时函数里面的this指向o6.f,而不是o6

    运行结果:

    如果想达到预期的效果:

     1 var o6={
     2     name:'cat',
     3     f:{
     4         f1:function(){
     5             console.log(this.name);
     6         },
     7         name:'cat'
     8     }
     9 }
    10 o6.f.f1();//cat

    继续进行变通:

     1 //将o6.f.f1赋值给变量
     2 var v=o6.f.f1;
     3 /**
     4  * 相当于
     5  * var v=function (){
     6  * console.log(this.name);
     7  * }
     8  */
     9 v();//this指向的对象又指向了顶层对象window
    10 //将o6.f赋值给变量
    11 var v1=o6.f;
    12 v1.f1();//此时返回的结果为'cat'
    13 /**
    14  * 相当于
    15  * var v1={
    16  * f1:function(){
    17  * console.log(this.name);},
    18  * name:'cat'
    19  * };
    20  */

    同时应尽量避免在函数中使用多层this

     1 //尽量避免在函数中使用多层this
     2 var o7={
     3     name:'apple',
     4     f:function(){
     5         console.log(this);//this指向当前运行环境对象,即o7
     6         var f1=function(){
     7             console.log(this);//this指向顶层对象,即window
     8         }();//IIFE;这是立即调用的函数表达式
     9     }
    10 };
    11 o7.f();

    运行结果:

    为了让f1中的this也指向该对象添加一个临时变量作为辅助:固定this

     1 var o8={
     2     name:'apple',
     3     f:function(){
     4         console.log(this);//this指向o8
     5         var that=this;//使用变量固定this
     6         var f1=function(){
     7             console.log(that);//此时that指向o8
     8         }();
     9     }
    10 };
    11 o8.f();

    运行结果:

    当然如果采用严格模式,那么函数内部this不能指向顶层对象window!

    由于this的灵活性,有时候难以把控。所以有三种绑定this的方法
    call,apply,bind
    三种方法中如果第一个参数为空、nullundefined,那么默认指向全局对象window

     call()调用函数指定this指向的对象;第一个参数是this指向的对象,第二个、第三个等是函数调用的参数

     1 var o9={
     2     name:'orange'
     3 };
     4 function test4(){
     5     console.log(this);
     6 }
     7 test4();
     8 test4.call(o9);//指定this的指向
     9 //call方法中如果参数为空、nullundefined,那么默认指向全局对象window
    10 test4(null);
    11 test4(undefined);
    12 //call方法第一个参数是this指向的对象,后面的参数是函数调用时用到的参数

    运行结果:

    call的一个应用:调用对象原生方法,即使该方法被覆盖

    1 var o10={};
    2 console.log(o10.hasOwnProperty('toString'));
    3 o10.hasOwnProperty=function(){
    4     return true;
    5 };
    6 console.log(o10.hasOwnProperty('toString'));
    7 //this指向o10,这样方法被覆盖,依然能够调用对象的原生方法
    8 console.log(Object.prototype.hasOwnProperty.call(o10,'toString'));

    运行结果:

    apply():作用与call()类似,第一个参数也是this指向的对象;不同的是函数调用的参数以数组形式传入

     1 //apply与call作用类似,只是apply传入的参数是以数组形式传入
     2 //同理,第一个参数是this指向的对象,空或null或undefined,默认是全局对象window
     3 function test6(a,b){
     4     console.log(a+b);
     5 }
     6 test6.call(null,1,10);//test6(1,10)
     7 test6.apply(null,[10,100]);//test6(10,100)
     8 var arr=[1,2,3,4,5];
     9 console.log(Math.max.apply(null,arr));//this指向window,arr调用Math.max方法
    10 console.log(Array.prototype.slice.apply({0:1,1:100,length:2}));//类似数组的对象调用方法变为数组

    运行结果:

    bind()将this绑定到某个对象,返回一个新函数(相较于call,apply的函数立即执行)

     1 //bind将this绑定到某个对象,并返回一个函数
     2 var o10={
     3     fruit:'apple',
     4     f:function(){
     5         console.log(this.fruit);
     6     }
     7 };
     8 o10.f();//正常取值
     9 console.log('---');
    10 var a=o10;
    11 a.f();//这样也能正确取值
    12 var b=o10.f;
    13 b();//这样取值就不行了;undefined
    14 /**
    15  * 此时this指向全局对象window,上面相当于
    16  * var b=function (){
    17  * console.log(this.fruit);//this指向window
    18  * }
    19  */
    20 
    21 //绑定this指向o10
    22 var c=o10.f.bind(o10);
    23 c();//此时能够正确取值

    运行结果:

    bind还能绑定函数的参数:

     1 //bind还可以绑定函数的参数
     2 var o10={
     3     name:'apple',
     4     age:100
     5 };
     6 function test7(x,y){
     7     console.log(x,this.name,y,this.age) ;
     8 }
     9 var t5= test7.bind(o10,'姓名信息: ');//绑定第一个参数,返回t5这个新函数
    10 t5(' 年龄信息: ');

    运行结果:

    参考:阮一峰JavaScript标准参考教程

  • 相关阅读:
    90. 子集 II 回溯算法
    47. 全排列 II 回溯算法
    40. 组合总和 II
    39. 组合总和 回溯
    NLP 第八课 语言技术-文本与LDA主题模型
    36. 有效的数独
    31. 下一个排列
    HDU 4527
    HDU 4521
    HDU 5191
  • 原文地址:https://www.cnblogs.com/why-not-try/p/8000058.html
Copyright © 2020-2023  润新知