首页 > 其他分享 >5. 函数

5. 函数

时间:2023-11-04 17:11:51浏览次数:28  
标签:function 闭包 console 函数 作用域 var

1. 函数

  • 函数是一个可重用的代码块,用来完成某个特定功能。每当需要反复执行一段代码时,可以利用函数来避免重复书写相同代码。

  • 函数包含着的代码只能在函数被调用时才会执行,就可以避免页面载入时执行该脚本

  • 在JavaScript中,可以使用以下三种方法来定义一个函数

    • 使用function语句定义函数

    • 使用Function()构造函数来定义函数

    • 在表达式中定义函数

1.1 函数的概念

  • 在JavaScript中,可能会编写非常多的相同的或者功能相似的代码,这些代码可以多次重复使用。

  • 函数:就是封装了一段可以被重复调用执行的代码块,通过此代码块可以实现大量的代码的重复使用。

  • 函数(又称为方法)用于对一大段为了达到某种目的的代码进行归类,以使代码更具有条理。

1.2 函数的使用

1.2.1 声明函数

语法:

function 函数名(){
    // 函数体
}

1.2.2 调用函数

1.直接调用

myFunction();或window.myFunction()

2.事件处理中调用

<div onclick="myFunction()"></div>

3.将函数的返回值赋给变量

var t = myFunction();

1.2.3 函数的封装

把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口。

 

1.3 函数的参数

  • 形参:在声明函数的小括号里面是形参(形式上的参数)

  • 实参:在调用函数的小括号里面是实参(实际上的参数)

  • 形参与实参个数不匹配

    • 实参多于形参,只取到形参的个数,可以在函数内部通过arguments关键字取到所有实参

      function foo() {
        console.log(arguments.length);  // 输出传递的参数个数
        console.log(arguments[0]);      // 输出第一个参数的值
        console.log(arguments[1]);      // 输出第二个参数的值
        // ...
      }
      ​
      foo(10, 'hello');
    • 实参少于形参,多的形参定义为undefined

1.4 函数的返回值

  • return语句

语法:

function 函数名(){
    return 需要返回的结果;
}
  • return语句之后的内容不再执行。

  • return只返回一个值,如果用逗号隔开多个值,只返回最后一个。

  • 如果函数有return,则返回return后面的值,如果函数没有return,则函数返回的结果undefined。

1.5 函数的两种声明方式

  • 命名函数(函数声明)

    function 函数名(){}

  • 函数表达式

    var 变量名 = function(){}

2 作用域

定义:

作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。

在JavaScript中,变量的作用域有全局作用域和局部作用域两种。

2.1 全局作用域(Global Scope)

在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域 :

1.最外层函数和在最外层函数外定义的变量拥有全局作用域

var authorName = '山边小溪';
function doSomething() {
    var blogName = '梦想天空';
    function innerSay() {
        console.log(blogName);
    }
    innerSay();
}
​
console.log(authorName);    // 山边小溪
console.log(blogName);  // 脚本错误
doSomething();  // 梦想天空
innerSay();     // 脚本错误

2.所有未定义直接赋值(没有var关键字)的变量自动声明为拥有全局作用域
function doSomething() {
    var authorName = '山边小溪';
  blogName = '梦想天空';
  console.log(authorName);
}
​
doSomething();  // 山边小溪
console.log(blogName);  // 梦想天空
console.log(authorName);    // 脚本错误

3.所有window对象的属性拥有全局作用域

一般情况下,window对象的内置属性都拥有全局作用域,例如window.name、window.location等

 

2.2 局部作用域(两种)(Local Scope)

函数作用域

和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的的就是在函数内部,所有也会看到有人把这种作用域称为函数作用域。

函数体内的变量声明(var声明的变量)会提前到函数体顶部,同时变量初始化还在原来的位置

// blogName和函数innerSay都只拥有局部作用域
function doSomething() {
    var blogName = '梦想天空';
  function innerSay() {
    alert(blogName);
  }
  innerSayName();
}
console.log(blogName);  // 脚本错误
innerSay();     // 脚本错误

ES6中的块级作用域

ES6 中新增了块级作用域。块作用域由 { } 包括,if 语句和 for 语句里面的 { } 也属于块作用域。

块级作用域由let声明变量,const声明常量

2.3 什么是作用域链

作用域链(Scope Chain)是指在嵌套的作用域中查找变量时依次检查的顺序。当需要访问一个变量时,JavaScript会从当前作用域开始搜索,直到找到该变量或搜索到达全局作用域。如果变量在作用域链中的某个地方找到,则可以访问该变量,否则将抛出引用错误。

3.自执行函数

自执行函数(Immediately Invoked Function Expression,IIFE)是一种在定义后立即执行的 JavaScript 函数。它的语法形式是将函数定义包裹在一对括号中,然后在后面加上一对空括号,如下所示:

(function() {
  // 函数体
})();

这样定义的函数会立即执行,并且不会在全局作用域中创建额外的变量。自执行函数常用于创建私有作用域、模块化开发和避免变量污染等场景。

自执行函数的效果

自执行函数可以用来保存变量的作用域,防止污染全局变量 以一个经典的面试题为例;

<ul>
  <li>这是第1个li</li>
  <li>这是第2个li</li>
  <li>这是第3个li</li>
  <li>这是第4个li</li>
  <li>这是第5个li</li>
  <li>这是第6个li</li>
</ul>

一个列表里有6个li,要求点击li的时候打印当前被点击li的索引。 如果我们直接通过for循环绑定事件:

var lis = document.querySelectorAll('li');
for(var i = 0;i<lis.length;i++){
  lis[i].onclick = function (){
    console.log(i)
  }
}
// 无论哪个li被点击,打印的永远都是相同的值,因为在所有的点击事件中,访问的都是全局的 i,当事件触发时,i的值已经变成是lis.length了。

在es6语法出现之后,我们使用 let 关键字创建的块级作用域可以解决这种问题,在 let 出现以前,通常是使用匿名函数+闭包的方式创建函数作用域来保存每一步循环里 i 的值;

var lis = document.querySelectorAll('li');
for(var i = 0;i<lis.length;i++){
  (function(i){
    lis[i].onclick = function (){
      console.log(i)
    }
  })(i)
}
// 使用这种方法,每次循环都会创建一个匿名函数,这个匿名函数生成了闭包的效果,新建了一个作用域,
// 这个作用域接收到每次循环的i值保存了下来,即使循环结束,闭包形成的作用域也不会被销毁;
// 事件处理函数中访问的 i 不再是全局变量,而且匿名函数中的局部变量。

闭包

什么是闭包:闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。 特点:

  1. 闭包就是一个特殊的函数

  2. 函数内部可以引用函数外部的参数和变量【能访问到其他作用域中的变量】

  3. 参数和变量不会被垃圾回收机制回收【延长变量的生命周期】

创建闭包

// 简单的闭包,
var num = 10;
function show(){
    console.log(num);
}
​
// 局部变量在全局使用
function show(){
  var num = 10;
  return function(){ // 闭包函数
    return num
  };
}
var b = show();
console.log(b());
​
// 局部变量
function f1(){
  var n=999;
}
​
// 局部变量在全局使用
function f1(){
  var n=999;
  function f2(){ 
    alert(n); // 999
  }
  return f2; // 闭包函数
}
f1()()
​
// 总结:闭包就是能够读取其他函数内部变量的函数。

案例:将普通函数改为闭包函数

// 普通函数
function show(){
  var m = 1;
  function inner(){
    var n = 0;
    console.log(++n);
    console.log(++m);
  };
  inner();
}
​
// 闭包函数
function show(){
  var m = 1;
  return function(){
    var n = 0;
    console.log(++n);
    console.log(++m);
  };
}

闭包的用途:

  1. 是前面提到的可以读取函数内部的变量

  2. 就是让这些变量的值始终保持在内存中。

闭包的缺点

比普通函数更占用内存,会导致网页性能变差,在IE下容易造成内存泄露。

什么是内存泄漏

首先,需要了解浏览器自身的内存回收机制。 每个浏览器会有自己的一套回收机制,当分配出去的内存不使用的时候便会回收;内存泄露的根本原因就是你的代码中分配了一些‘顽固的’内存,浏览器无法进行回收,如果这些’顽固的’内存还在一直不停地分配就会导致后面所用内存不足,造成泄露。

闭包造成内存泄漏

因为闭包就是能够访问外部函数变量的一个函数,而函数是必须保存在内存中的对象,所以位于函数执行上下文中的所有变量也需要保存在内存中,这样就不会被回收,如果一旦循环引用或创建闭包,就会占据大量内存,可能会引起内存泄漏 闭包参考文档:https://www.cnblogs.com/huanxiongs02/p/14698192.html

函数案例

 //冒泡排序
         var arr = [3,8,6,1,9,5]
        function sort(arr){
            var temp;
            for(var i=0; i<arr.length-1; i++){
                for(var j=0; j<arr.length-1-i; j++){
                    if(arr[j] > arr[j+1]){
                        temp = arr[j+1]
                        arr[j+1] = arr[j]
                        arr[j] = temp
                    }
                }
            }
            return arr
        }
        console.log(sort(arr));
// 获取数组中的最大值
        function getMax(arr){
            var newArr = arr.sort(function(a,b){
                return b - a;
            })
            return newArr[0];  
            var max = arr[0];
            for(var i=1;i<arr.length;i++){
                if(arr[i]>max){
                    max = arr[i];
                }
            }
            return max;
        }
        console.log(getMax([6,3,8,23,45,1,99]));
//反转数组
// 方法一 function reverse(arr){ var newArr = []; for(var i=0;i<arr.length;i++){ newArr[arr.length-i-1] = arr[i]; } return newArr; } var arr1 = reverse([1,4,7,9,12,16]); console.log(arr1); // 方法二 function reverse(arr){ var newArr = []; for(var i=arr.length-1;i>=0;i--){ newArr[newArr.length] = arr[i] } return newArr; } var arr1 = reverse([1,4,7,9,12,16]); console.log(arr1);

 

标签:function,闭包,console,函数,作用域,var
From: https://www.cnblogs.com/c-pp/p/JavaScript_4.html

相关文章

  • JS 工具函数
    1、校验数据类型exportconsttypeOf=function(obj){returnObject.prototype.toString.call(obj).slice(8,-1).toLowerCase()}示例:typeOf('树哥')//stringtypeOf([])//arraytypeOf(newDate())//datetypeOf(null)//nulltypeOf(true)//boolea......
  • 封装函数
    //编写程序,获取数组中的最大值//functionarr(arr){//varmax=[];//for(vari=0;i<arr.length;i++){//if(arr[i]>max){//max=arr[i]//}//}//returnmax;//......
  • JavaScript函数变量的生命周期,自执行函数、闭包、反转数组案例及冒泡排序案例
    一、变量的生命周期JavaScript变量的生命期从它们被声明的时间开始。局部变量会在函数运行以后被删除。全局变量会在页面关闭后被删除。二、自执行函数执行函数通常都是定义之后立即执行,以后都不再会调用,所以声明时可以省略函数名,因此自执行函数又叫匿名函数。通用的自执行......
  • 实验3 C语言函数应用编程
    任务11#include<stdio.h>2#include<stdlib.h>3#include<time.h>4#include<windows.h>5#defineN8067voidprint_text(intline,intcol,chartext[]);8voidprint_spaces(intn);9voidprint_blank_lines(intn......
  • JavaScript如何定义类与函数如何实现继承自Object类实现方法------前端
    HTML页面用于展示<!DOCTYPEhtml><!--这是HTML的注释--><htmllang="en"id="myHtml"> <head> <!--这里不是设置了编码,而是告诉浏览器,用什么编码方式打开文件避免乱码--> <metacharset="UTF-8"> <metaname="viewport"......
  • JavaScript 函数、函数构造、函数调用、参数、函数返回值、变量的作用域、预解析
    一、函数及函数的构造函数是一个可重用的代码块,用来完成某个特定功能。每当需要反复执行一段代码时,可以利用函数来避免重复书写相同代码。函数包含着的代码只能在函数被调用时才会执行,就可以避免页面载入时执行该脚本简单来说就是一个封装,封装的是一个特定的功能,重复使用函......
  • 如何求函数的对称中心和对称轴|探究拓宽
    预备知识1、多项式函数\(y=f(x)=ax^4+bx^3+cx^2+dx+e\)为奇函数的充要条件是\(a=c=e=0\).分析:由于函数\(f(x)\)为奇函数,故有\(f(-x)+f(x)=0\)恒成立,即\(\bigg[a(-x)^4+b(-x)^3+c(-x)^2+d(-x)+e\bigg]\)\(+\)\(\bigg(ax^4+bx^3+cx^2+dx+e\bigg)=0\)恒成立,即\(2a\cdotx......
  • Python分享之内置函数清单
    Python内置(built-in)函数随着python解释器的运行而创建。在Python的程序中,你可以随时调用这些函数,不需要定义。最常见的内置函数是:print("HelloWorld!")在Python教程中,我们已经提到下面一些内置函数:基本数据类型type()反过头来看看dir()help()len()词典len()文本文......
  • 一些有用的css函数
    var使用自定义的属性值。:root{--main-bg-color:pink;}body{background-color:var(--main-bg-color);}attr使用html上data-*属性引用的文本。<pdata-foo="hello">world</p>p:before{content:attr(data-foo)"";}属性也可以被解析为colo......
  • 实验3—C语言函数应用编程
    1、实验任务1源代码1#include<stdio.h>2#include<stdlib.h>3#include<time.h>4#include<windows.h>5#defineN806voidprint_text(intline,intcol,chartext[]);//函数声明7voidprint_spaces(intn);//函数声明8voidprint_b......