• JS 函数—函数内部:arguments、this、,caller、new.target


     1.arguments & callee

    arguments 对象,它是一个类数组对象,包含调用函数时传入的所有参数。这个对象只有以function关键字定义函数(相比于使用箭头函数)时才会有。这里说一下arguments对象的callee属性,是一个指向arguments对象所在函数的指针。
    示例:一个经典的阶乘函数
    1 function factorial(n){
    2     if(n <=1 ){
    3         return 1
    4     }else{
    5         return n * factorial(n-1)
    6     }
    7 }
    8 
    9 factorial(5)  // 120

    这样写的问题是:紧耦合。如果这个函数的名称改变了,函数内部的代码也需要改变。使用arguments.callee可以让函数逻辑与函数名解耦:

    1 function factorial(n){
    2     if(n <=1 ){
    3         return 1
    4     }else{
    5         return n * arguments.callee(n-1)
    6     }
    7 }
    8 
    9 factorial(5)  // 120
    注意:严格模式下禁用了arguments.callee

    2.this

    函数中的另一个特殊对象是this,它在标准函数和箭头函数中有不同的行为。

    (1)标准函数中

    在标准函数中,this 引用的是把函数当成方法调用的上下文对象,这时候通常称其为 this 值(在网页的全局上下文中调用函数时,this 指向 windows)。
    1     window.n =1
    2 
    3     function fn(){
    4         console.log(this.n);
    5     }
    6 
    7     fn()  // 1

     定义在全局上下文中的函数 sayColor()引用了 this 对象。这个 this 到底引用哪个对象必须到函数被调用时才能确定。因此这个值在代码执行的过程中可能会变。

    (2)箭头函数中

    在箭头函数中,this引用的是定义箭头函数的上下文。

    1     window.n =1
    2     let o = {
    3         n : 9
    4     }
    5 
    6     let fn = ()=> console.log(this.n);
    7     fn()  // 1
    8     o.fn = fn
    9     fn()  // 1
    在事件回调或定时回调中调用某个函数时,this指向的并非想要的对象。此时将回调函数写成箭头函数就可以解决问题。因为箭头函数中的this会保留定义该函数时的山下文:
     1     window.uname = "王五"
     2 
     3     function People(){
     4         this.uname = '张三'
     5     setTimeout(() => console.log(this.uname) ,0)
     6     }
     7 
     8     function Obj(){
     9         this.uname = "李四"
    10         setTimeout(function(){console.log(this.uname)} ,0)        
    11     }
    12 
    13     new People()  // 张三
    14     new Obj()  // 王五

     注意

    • 函数名只是保存指针的变量。因此全局定义的 sayColor()函数和 o.sayColor()是同一个函数,只不过执行的上下文不同。

    3.caller

    ES5在函数对象上也添加了一个属性:caller。这个属性引用的是调用当前函数的函数,或者

     1     function outer(){
     2         inner()
     3         console.log(123);
     4     }
     5 
     6     function inner(){
     7         console.log(inner.caller);
     8     }
     9 
    10     outer()
    11     /**
    12      ƒ outer(){
    13         inner()
    14         console.log(123);
    15     }
    16     */

    以上会显示outer()函数的源代码。这是因为outer()调用了inner()inner.caller指向outer().。如果要降低耦合度,则可以通过arguments.callee.caller来引用同样的值:

     1     function outer(){
     2         inner()
     3         console.log(123);
     4     }
     5 
     6     function inner(){
     7         console.log(arguments.callee.caller);
     8     }
     9 
    10     outer()
    11     /**
    12      ƒ outer(){
    13         inner()
    14         console.log(123);
    15     }
    16     */

    注意:严格模式下禁用了arguments.callee

     4.new.target

    JS中的函数始终可以作为构造函数实例化一个新对象,也可以作为普通函数被调用。ECMAScript 6 新增了检测函数是否使用 new 关键字调用的 new.target 属性。如果函数是正常调用的,则 new.target 的值是 undefined;如果是使用 new 关键字调用的,则 new.target 将引用被调用的构造函数。

    1     function King() {
    2         if (!new.target) {
    3             throw 'King must be instantiated using "new"'
    4         }
    5         console.log('King instantiated using "new"');
    6     }
    7     new King(); // King instantiated using "new" 
    8     King(); // Error: King must be instantiated using "new"
  • 相关阅读:
    SQL语言的组成
    存储过程中使用事务
    sql语法:inner join on, left join on, right join on详细使用方法
    Sql Server服务 远程过程调用失败
    UML学习之初步总结
    UML学习之用例图
    使用redis
    msserver的update or insert语句
    c#操作注册表的意外
    托管代码编写mssql存储过程
  • 原文地址:https://www.cnblogs.com/codexlx/p/14335027.html
Copyright © 2020-2023  润新知