💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
目标: * 如何定义和使用函数 * 如何向函数传递参数 * 了解预定义函数(内建函数) * 了解变量作用域 ⭐ * “函数也是数据” * 匿名函数的调用 * 回调函数 * 自调函数 ⭐ * 内嵌函数 * 以函数为返回值的函数 ⭐ * 能重定义自身的函数 * 闭包 ⭐ ***** # 函数 实质为代码分组形式,便于重用; 组成:`function + 函数名 + 参数 + 函数体(代码块) + return (undefined)` 调用/请求:函数名 + ([参数]) 传递的参数,少了,参数设为undefined,多了,忽略。 函数内建有**arguments**数组(类似数组的对象),可返回所接收的全部参数。 ``` function args(){return arguments;} args(); // Arguments [callee: ƒ, Symbol(Symbol.iterator): ƒ] args(1,2,3,4,true); // Arguments(5) [1, 2, 3, 4, true, callee: ƒ, Symbol(Symbol.iterator): ƒ] ``` # 内建函数 * parseInt() * parseFloat() * isNaN() * isFinite() * encodeURI() * decodeURI() * encodeURIComponent() * decodeURIComponent() * eval() ***** ## parseInt(a1,radix) 将a1转换成整数类型,失败返回NaN; 最好指明radix进制。 ``` parseInt('abc123') // NaN parseInt('123abc') // 123 在遇到第一个异常字符时会放弃转换 ⭐ parseInt(NaN); // NaN parseInt(1e1) // 10 parseInt('1e1'); // 1 ``` `radix`一般默认为10,即10进制,例外情况: 首参数字符串是0x开头,radix=16; 首参数字符串是0开头,radix=8; ## parseFloat(a) 只支持转换为10进制数,多余参数会忽略 可转换指数数据,parseInt不支持 ⭐ ``` parseFloat('123e2'); // 12300 parseInt('123e2', 10); // 123 parseFloat('1e1'); // 10 ``` ## isNaN() 用于判断输入值是否是非数值,`true-非数,false-数值`,即返回false才可作算术运算 ``` isNaN('a'); // true isNaN('123'); // false isNaN(parseInt(NaN)); // true ``` ## isFinite() 检查输入是否一个既非infinity也非NaN数字,是否有限数值,true-有限 ``` isFinite(Infinity); // false isFinite(12); // true ``` ## URI编码与解码 `encodeURI()`——域名部分不编码 `encodeURIComponent()`——全部编码 `decodeURI()`——域名部分不编码 `decodeURIComponent()`——全部编码 ## eval() 欺骗函数,类似Function() 将传入的string作为代码执行,动态代码, * 性能差; * 安全性差; ## alert() # 变量的作用域 ⭐ 全局变量:声明在所有函数之外的变量; 局部变量:声明在某个函数内部的变量,在该函数外是不可见的。 > 声明一个变量如果没有使用var语句,该变量会被默认为全局变量! > 减少全局变量的数量 函数域优先于全局域 ``` var a= 123; function f() { alert(a); var a = 1; // 局部变量a声明被提升至函数域顶部,只声明被提升! alert(a); } f(); // undefined 1 ``` # 函数也是数据 函数标识记法,像变量一样使用函数 函数名不能以数字开头; ``` // function f(){return;} var f = function(){return;} typeof f; // "function" ``` 函数特性: * 它们所包含的是代码; * 它们是可执行的; ## 匿名函数 两种用法: * 将匿名函数作为参数传递给其他函数; * 定义匿名函数来执行某些一次性任务; ## 回调函数 Callback() 将函数A传递给函数B,由B来执行A,A就是一个(匿名)回调函数 优势: * 匿名传递函数,节省全局变量; * 将调用A的操作委托给B,节省代码量; * 提升性能; ## 自调函数 IIFE `(function(参数){函数体})('入参')` ## 内部(私有)函数 好处: * 确保全局名字空间的纯洁性; * 私有性,暴露该暴露的,封装其余的; ## 返回函数的函数 `return function(){...};` ## 能重写自己的函数 利用返回函数覆盖旧函数; 执行一次性初始化工作; * 外部重写; * 内部重写; ``` function a(){ alert('A!'); a = function(){ alert('B!'); } } a(); // A! a(); // B! ``` "浏览器特性探测"技术实现原理 # 闭包 ## 作用域链 在函数中可访问的变量,既可以来自自身作用域,也可以来自其父级作用域。这就是一条作用域链(scope chain)。 ## 词法作用域 每个函数在被**定义时**都会创建一个属于自己的环境(作用域) ``` function f1(){var a = 1; f2();} function f2(){return a;} f1(); // Uncaught ReferenceError: a is not defined ``` 我们可以在函数中对变量执行添加、移除和更新等操作,但函数只会看到该变量的最终状态。因此我们可以重写函数执行体,依旧能正常工作。 ## 利用闭包突破作用域链 将函数移动到词法作用域以外,函数仍记得其所定义作用域的路径,保持着对原定义作用域的引用,依旧可以访问原作用域的变量。 ### 闭包1 ``` function f(){ var b = 'b'; return function(){ return b; } } b; // Uncaught ReferenceError: b is not defined var n = f(); // n 为全局变量,可以访问f()私有空间 n; // ƒ (){ return b; } n(); // "b" ``` ### 闭包2 ``` var n; function f(){ var b = "b"; n = function(){ return b; } } f(); n(); // "b" ``` ### 闭包3 函数绑定的是作用域本身,而非变量或返回值 ``` function f(arg){ var n = function(){ return arg; } arg++; return n; } var m = f(123); m(); 124 ``` ## Getter & Setter 通过匿名自调函数,供全局函数间接访问局部变量secret ``` var getValue, setValue; (function(){ var secret = 0; getValue = function(){ return secret; }; setValue = function(v){ secret = v; }; })() getValue(); // 0 setValue(123); getValue(); // 123 ```