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"
原文地址:https://www.cnblogs.com/codexlx/p/14335027.html