第7天

168 阅读5分钟

Day 7

函数

将一些功能或语句进行封装,在需要的时候调用来执行这些语句,特别是重复的

作用:

  • 避免重复劳动
  • 模块化

例如写一个从1加到N求和的函数

// 封装函数
function addNn{
var sum = 0
for(var i = 0;i <= n;i++){
sum += 1
}
console.log(sum)
}

函数是一个对象,是一个函数对象,用typeof来看返回一个function

函数定义/声明

  • 方式一、使用函数声明来创建一个函数

    • function 变量名(参数){

      代码}

      • 如果没有名字如何调用?会报错,必须要有名字。
        • *除非声明之后立即调用(也即立即执行函数/匿名函数)
  • 方式二、使用函数表达式来创建

    • 匿名函数(没有函数名称)
var addN = function(){
代码
}
  • 关于匿名函数看后面。

  • 方式一与方式二这两种有什么区别?

    • 变量的声明提升。

      console.log(fn) //虽然是写在前面
      
      var fn = function(){	// 但是这里会进行变量的声明提前
      	console.log(123)
      }
      
      function fn(){	// 这里将整个函数提升到最前面
      	console.log(777)
      }
      
    • 方式一直接将整个函数声明,但是是提升到最前面

    • 方式二也会声明提升,但不会进行赋值

    • 如果同时写两个方式,那么只会是方式一的

变量的作用域(Scope)

作用域有两个:全局作用域和函数作用域。也即变量生效的范围

  • 直接写在script标签中的js代码,都在全局作用域。
    • 全局作用域在页面打开是创建,关闭时销毁
    • 不在函数内声明的变量,都是全局变量。
      • 所有的全局变量都会放在window的属性中。
        • window代表的是一个浏览器的窗口,由浏览器创建(不用我们创建)且我们可以直接使用
    • 在全局作用域中:
      • 创建的变量都会作为window对象的属性保存。
      • 创建的函数都会作为window对象的方法保存。
    • 函数作用域是可以访问到全局变量的
  • 局部作用域(函数作用域)
    • 在函数中声明一个变量var = 变量,再函数外输出这个变量是没用的。
      • 全局作用域无法访问到函数作用域的变量
    • 在函数中声明,只在函数中有效。
      • 但如果没有声明var,而是直接变量 = 值,那么会自动声明成全局变量。

执行期上下文

变量在用完(函数执行完)之后是会再内存中被销毁的。

  • 那么如何保留变量不被销毁?(执行期上下文被销毁的例外情况)
    • 某函数的变量被另一个函数外部引用的时候,就不会在函数执行完毕后销毁

定义形参,其实就是在函数作用域中声明了变量

函数的参数

  • 形式参数(形参),声明里的参数

  • 实际参数(实参),实际调用的参数。形参相对于实参来说的。

  • 注意:JS中不会对实际传入的参数检测,

    • 实际调用的时候,可以传部分值,也可以不传值,还可以传超过声明的值
      • 不传值可能会undefined
      • 多传值,也不会报错,多余的没啥用
  • 如果不知道你传多少个值,但又想都起作用(比如把你传的参数都加起来),可以用arguments

    • arguments。用来获取所有实际传递的参数

    • function add(){
      console.log(arguments)
      forvar i = 0;i<arguments.length;i++){
      sum = sum + arguments[i]
      }
      }
      add(1,2,3,4,999)
      

函数的返回值

注意return和console.log的区别

return和console。log,没有一点关系

return的意思是:

  • return后面的值,会作为最终的结果返回

    • 可以定义一个变量来接收

    • function add(){
      console.log(arguments)
      forvar i = 0;i<arguments.length;i++){
      sum = sum + arguments[i]
      }
      }
      var result = add(1,2,3,4,999)//定义变量接收
      comsole.log(result)
      
  • 结束方法

    • return后面的语句都不会执行
  • 如果return后不跟任何值,则默认返回undefined

  • 如果不写return的话也默认返回undefined

  • 返回值可以是任何的数据类型,甚至还可以是一个函数

    • <script type="text/javascript">
      			function add(a,b){
      				var outResult = function(){
      					return a+b;
      				}
      				return outResult	//返回函数
      			}
      			
      			var a = add(3,4)
      			console.log(a)	// 输出变量(是一个函数)
      			console.log(a());	//输出函数值
      		</script>
      
    • <script type="text/javascript">
      			function add(a,b){
      				var outResult = function(){
      					return a+b;
      				}
      				return outResult()	//返回函数值
      			}
      			
      			var a = add(3,4)
      			console.log(a)	// 输出变量(函数值)
      		</script>
      

函数名、函数体和函数加载问题

  • 函数名 == 函数整体
    • 不加括号的函数(可以见上一小节最后两个js的对比
    • fn():调用函数。相当于获取函数返回值
    • fn:函数对象。相当于直接获取整个函数对象、
      • 例如直接console。log(函数名称)
  • js加载的时候只加载函数名而不加载函数体。若要使用内部的变量,则需要调用函数。

立即执行函数

现有匿名函数如下:

    function(a, b) {
        console.log("a = " + a);
        console.log("b = " + b);
    };

立即执行函数如下:(也即加括号)

    (function(a, b) {
        console.log("a = " + a);
        console.log("b = " + b);
    })(123, 456); //一定要注意分号
  • 为什么需要这种立即执行函数呢?
    • 不会创建全局作用域
    • 多人合作写代码的时候,变量名称重复的时候是不会报错的,那怎么找BUG呢?就用匿名函数,并且只在函数中声明,也即局部变量