JavaScript【八】JavaScript函数高级

简介: JavaScript【八】JavaScript函数高级

🌟前言

哈喽小伙伴们,本文将收录在JavaScript【前端童子功】这个专栏里;这个专栏里边会收录一些JavaScript的基础知识和项目实战;希望大家可以多多支持,你们的支持就是我创作的动力;让我们一起来看看吧🤘

🌟回调函数

js代码会至上而下一条线执行下去,但是有时候我们需要等到一个操作结束之后再进行下一个用户操作,这时候就需要用到回调函数来控制下一个操作的功能。

把一个函数的指针作为另一个函数的参数,当调用这个参数时,被当做参数的这个函数就叫 回调函数

function A(callback) {
    callback();
    console.log('主函数');
}
function cb(){
    console.log("回调函数")
}
A(cb)

把函数整体作为参数传进去

function A(callback) {
    callback();
    console.log('主函数');
}
A(function (){
    console.log("回调函数")
})

传参给回调函数

function A(callback) {
    var str = "传递给回调的参数";
    callback(str);
    console.log('主函数');
}
A(function (str){
    //str 是接收主函数传递的参数
    console.log("主函数传递的参数为",str);
    console.log("回调函数");
})

在执行回调的时候确保它是个函数

function Fn(options, callback) {
    if (typeof callback === "function") {
        callback(options);
    }
}

示例:封装each函数简化for循环

function each(n,callback){
    for(var i=0;i<n;i++){
        callback(i)
    }
}
each(10,function(i){
    console.log(i)
})

🌟递归函数

所谓的 递归函数 就是在函数体内调用本函数。使用递归函数一定要注意,处理不当就会进入死循环。

  • 在函数内部直接或间接引用自身。
  • 每个递归函数里必定会有终止条件。

求阶乘

function factorial(c){
  if(c == 1){
      return c;
  }else{
      return c * factorial(c-1);
  }
}
alert(factorial(5));

多维数组遍历

var new_array=[];
function _getChilds(data){
    if(typeof data != "object" || data == null){
        new_array.push(data);
    }else{
        getChilds(data);
    }
}
function getChilds(data){
    for(var i in data){
        _getChilds(data[i]);
    }
}
var json = {
    "aa" : {"l" : 1,"m" : 3},
    "bb" : 1,
    "cc" : "abc",
    "dd" : true,
    "ee" : null
}
getChilds(json)
console.log(new_array)

🌟闭包

闭包是JavaScript语言的一大特点,主要应用场合为:设计私有的方法和变量。

🌟什么是闭包函数?

理解闭包前,需要先理解 全局作用域和局部作用域 的区别。函数内部可以访问全局作用域下定义的全局变量,而函数外部却无法访问到函数内部定义(局部作用域)的局部变量。

  • 概念: 闭包(closure)是定义在一个外部函数内部,并且能够访问外部函数中变量的函数。
  • 原理: 作用域链

创建闭包的常见方式,就是在一个函数内部创建另一个函数并返回:

function fun(num){
    return function (){
        return num;
    }
}
var end = fun(100);
end();  //  100

上述案例中,num 是fun函数内部的变量,本来只能fun函数内部使用,但是返回的函数也有权限访问num。所以在函数外部通过调用返回的函数即可得到函数内部的变量

function out (){
   var n = 1;
   return function (){
       return n++;
} }
var fn = out();
console.log(fn()) //1
console.log(fn()) //2
console.log(fn()) //3

🌟 闭包三个特性

  1. 函数嵌套函数
  2. 函数内部可以引用外部的参数和变量
  3. 参数和变量不会被垃圾回收机制回收

🌟 闭包的缺点

闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄漏。 一般函数执行完毕后,局部活动对象就会被销毁,内存中仅仅保存全局作用域。但闭包的情 况不同。

🌟JavaScript的垃圾回收机制

  1. 在JavaScript中,如果一个对象不再被引用,那么这个对象就会被GC回收。
  2. 如果两个对象互相引用,而不被第三者所引用,那么这两个互相引用的对象也会被回收。

🌟闭包小案例

那么使用闭包有什么好处呢?

  1. 希望一个局部变量长期驻扎在内存中
  2. 避免全局变量的污染
  3. 私有成员的存在

🌟局部变量长期驻扎内存

function out (){
    var n = 1;
    return function (){
        return n++;
    }
}
var fn = out();
console.log(fn())
console.log(fn())
console.log(fn())

在循环中直接找到对应的元素的索引

注/ <ul>
  <li>1111111</li>
  <li>1111111</li>
  <li>1111111</li>
</ul>
var lis=document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++){
   (function(i){
       lis[i].onclick=function(){
           alert(i);//0 1 2
       }
   })(i)
}
for(var i=0;i<10;i++){
    setTimeout(function(){
        console.log(i);    //10
    }, 1000)
}

🌟避免全局变量污染

但我们声明一个函数的时候其实就相当于创建一个全局变量 上一个例子中总共占有2个全局变量。

函数表达式 函数自调用:

(function(){
})()
 var out = (function(){
    var n1 = 1;
    var n2 = 100;
    return function(){
        n1++;
        n2--;
        return n1+n2;
} })()
out() // 1
out() // 2

🌟私有成员的存在

模块化代码

var aa=(function(){
   var a=10;
   function aaa(){
       a++;
       alert(a);
   }
   function bbb(){
       a+=10;
       alert(a);
   }
   return {
      a:aaa,
      b:bbb
   }
})()
aa.a(); //11
aa.b(); //21

这样做的好处就是 bbb aaa 这两个函数我们在外面是访问不到的

由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。

🌟[ES6]块级作用域

🌟什么是块级作用域

JS中作用域有:全局作用域、函数作用域。没有块作用域的概念。ECMAScript 6(简称ES6)中新增了块级作用域。

块作用域由 { } 包括,if语句和for语句里面的{ }都属于块作用域。

ES5没有块级作用域概念:

{
  var num = 10;
}
console.log(num)    // 10
// for循环结束后,变量i依然会存在
for(var i = 10; i<5;i++){ }
console.log(i);   // 5

ES6的块级作用域:

{
  let num = 10;
}
console.log(num)    // 报错: num is not defined
// 由于i是存在于块级作用域中,所以i只能在循环{}中使用
for(let i = 10; i<5;i++){ }
console.log(i);   // 报错: i is not defined

🌟 函数声明与块级作用域

  • ES5中,函数只能在顶层作用域和函数作用域中声明,不能在块级作用域中声明。
  • ES6中,在块级作用域内部声明的变量函数,其行为类似于let,即块级作用域外不可使用
  function fun(){
    console.log("I am outside function.")
  }
  if (true) {
    function fun() {
      console.log("I am inside function.");
    }
    fun();    // I am inside function.
  }
  fun();    // I am inside function.
  'use strict'      //es6 中的运行结果
  function fun(){
    console.log("I am outside function.")
  }
  if (true) {
    function fun() {
      console.log("I am inside function.");
    }
    fun();    // I am inside function.
  }
  fun();    // I am outside function.

🌟函数扩展

🌟[ES6]函数参数的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构

只需要保证实参和形参数据类型同为数组或对象,即可进行函数参数的解构赋值:

function add([x, y]){
  return x + y;
}
add([1, 2]); // 3
function fun({num1:x, num2:y}) {
  return x + y;
}
fun({num1: 1, num2: 2})  // 3

🌟[ES6]箭头函数

🌟 基本用法

ES6允许使用“箭头”(=>)定义函数。

var f = v => v;


上面的箭头函数等同于:

var f = function(v) {
return v;
};


  • 如果箭头函数不需要参数,就使用一个()_代表参数部分。
  • 如果箭头函数需要多个参数,就使用一个()代表参数部分。
var f = () => 5;
var f = _ => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来。

var sum = (num1, num2) => {
    console.log(num2);
    console.log(num1);
return num1 + num2;
}
console.log(sum(1,2));     // 2  1  3

由于大括号被解释为代码块,所以如果箭头函数直接返回一个json,必须在对象外面加上括号。

var person = age => ({ name: "Tom", age: age});
console.log(person(21));     //Object {name: "Tom", age: 21}

箭头函数可以与变量解构结合使用。

var full = ({ name, age}) => name + '-' + age;
console.log(full({name:"Tom",age:21}));     // Tom-21

箭头函数使得表达更加简洁。

const isEven = n => n % 2 == 0;
const square = n => n * n;

箭头函数的其中一个用处是简化回调函数。

// 正常函数写法
var arr1 = [1,2,3].map(function (x) {
return x * x;
});
console.log(arr1);    //[1,4,9]
// 箭头函数写法
var arr2 = [1,2,3].map(x => x * x);
console.log(arr2);    //[1,4,9]

🌟使用注意点

  1. this对象的指向是可变的,但是在箭头函数中,它是固定的。
function foo() {
setTimeout(() => {
  console.log('id:', this.id);
}, 100);
setTimeout(function () {
  console.log("id:",this.id);
},100)
}
var id = 21;
foo.call({ id: 42 });
//id: 42
//id: 21


  1. 不能当做构造函数
  2. 箭头函数没有arguments对象



🌟写在最后

更多JavaScript知识以及API请大家持续关注,尽请期待。各位小伙伴让我们 let’s be prepared at all times!


目录
相关文章
|
1月前
|
JavaScript 前端开发 Java
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
本文介绍了JavaScript中常用的函数和方法,包括通用函数、Global对象函数以及数组相关函数。详细列出了每个函数的参数、返回值及使用说明,并提供了示例代码。文章强调了函数的学习应结合源码和实践,适合JavaScript初学者和进阶开发者参考。
42 2
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
|
1月前
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
2月前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
2月前
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
|
3月前
|
JavaScript 前端开发 安全
JavaScript函数详解
JavaScript函数的详细解析,包括函数的定义和调用方式(如一般格式、匿名函数、构造函数、自调用函数、箭头函数和严格模式)、函数参数(arguments对象、可变参数、默认参数值)、闭包的概念和应用实例。
JavaScript函数详解
|
2月前
|
JavaScript 前端开发
js教程——函数
js教程——函数
44 4
|
2月前
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
21 2
|
2月前
|
JavaScript 前端开发 Java
【javaScript数组,函数】的基础知识点
【javaScript数组,函数】的基础知识点
28 5
|
2月前
|
JavaScript 前端开发
Node.js 函数
10月更文挑战第5天
25 3
|
2月前
|
前端开发 JavaScript
探索JavaScript函数基础
探索JavaScript函数基础
20 3
下一篇
DataWorks