【js学习笔记-046】-- 函数

来源:互联网 发布:阿里云看我的订单 编辑:程序博客网 时间:2024/06/10 20:58

js,函数即对象,程序可以随意操控它们。比如,js可以把函数赋值给变量,或者作为参数传递给其它函数。因为函数就是对象,所以可以给它们设置属性,甚至调用它们的方法。

   js的函数可以嵌套在其它函数中定义,这样它们就可以访问它们被定义时所处的作用域中的任何变量。这意味着js函数构成了一个闭包,它给js带来了非常强劲的编程能力。

函数声明:

注意声明式函数和函数表达式的区别,声明式函数会把函数声明提到脚本和外部函数的顶部,所以这种声明方式的函数,可以被在它定义之前出现的代码所调用。函数表达式,要调用它,必须要能引用它,而要使用一个以表达方式定义的函数之前,必须把它赋值给一个变量。变量声明提前,而变量赋值不会提前,所以,以表达式方式定义的函数在定义之前无法调用。

嵌套函数:

嵌套函数的有趣之处在于它的变量作用域规则:它们可以访问嵌套它们的函数的参数和变量。

注意:声明函数语句并非真正的语句,ECMAScript规范只是允许它们作为顶级语句。它们可以出现在全局代码里,或内嵌在其它函数中,但它们不能出现在循环、条件判断,或者try/cache/finally以及with语句中。以上仅限声明式函数,如果是函数表达式,则可以出现在代码的任何地方。

函数调用:

构成函数主体的js代码在定义之时并不会执行,只有调用该函数时,它们才会执行。4种方式调用js函数

1.        作为函数

2.        作为方法

嵌套函数不会从调用它的函数中继承this.如果嵌套函数作为方法调用,其this的值指向调用它的对象。如果嵌套函数作为函数调用,this值不是全局对象就是undefined很多人误以为调用嵌套函数时this会指向调用外层函数的上下文

方法链:当方法的返回值是一个对象,这个对象可以再调用它的方法。这种方法调用序列中每次的调用结果都是另外一个表达式的组成部分。

当方法并不需要返回值时,最好直接返回this。如果在设计的API一直采用这种方式,使用API就可以进行链接调用。此链式调用不同于构造函数的链式调用

3.        作为构造函数

如果函数或方法前带有关键字new,它就构成构造函数调用。构造函数调用与普通方法调用在实参处理,调用上下文,返回值方面都有所不同。

有参数:先计算实参表达式,然后传入函数内,这和函数调用和方法调用是一致的。如果没有参数,构造函数调用允许省略实参列表和圆括号。如下:

   var obj = new  Object();

   var obj = new  Object; //=>两者等价!

  创建新对象,并将这个对象用做其调用上下文,这个对象继承自构造函数的prototype属性。因此构造函数可以使用this关键字来引用这个新创建的对象。注意:尽管构造函数看起来像一个方法调用,它依然会使用这个新对象作为调用上下文。也就是说,在表达new  o.m()中,调用上下文并不是o

构造函数并不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。然而如果构造函数使用return显式返回一个对象那么调用表达式值就是这个对象。如果构造函数使用return 没有返回值或返回一个原始值。那么这时将忽略返回值,同时使用这个新对象作为调用结果。

 进一步理解:

为什么用new关键字构造出来的a,会获得p这个属性?new A()这行代码做了什么事情?根据上篇文章中Function的创建过程第4步,A这个对象会有一个Construct属性(注意不是constructor,Consturct是ECMAScript标准里的属性,好像对外不可见),该属性的值是个函数,new A()即会调用A的这个Construct函数。那么这个Construct函数会做些啥呢?
  1, 创建一个object,假设叫x。
  2, 如果A.prototype是个object(一般都是),则把A.prototype赋给x.__proto__;否则(不常见),请大老板Object出马,把Object.prototype赋给x.__proto__。
  3, 调用A.call(x),第一个参数传入我们刚刚创建的x。这就妥了,A的函数体里this.p = 1,这个this,就成了x。因此x就有了p这个属性,并且x.p = 1。
  4, 一般情况下,就返回x了,这时a就是x了。但也有特殊情况,如果A的函数体里返回的东西,它的类型(typeof)是个object。那么a就不是指向x了,而是指向A函数返回的东西。
伪代码如下:
 
var x = new Object(); //事实上不一定用new来创建,我也不清楚。
x.__proto__ = A.prototype 
var result = A.call(x)
if (typeof(result) == "object"){
  return result;
}
return x;


4.        通过它们的call和apply()方法间接调用

5.        arguments对象的callee和caller属性

         callee在ECMAScript标准规范中规定它所代表当前正在执行的函数

         caller是非标准的,但大多数浏览器都实现了它个属性它指代调用当前正在执行的函数的函数通过caller属性可以访问调用堆栈。

原创粉丝点击