js 函数
发布日期:2022-02-08 04:20:56
浏览次数:5
分类:技术文章
本文共 11255 字,大约阅读时间需要 37 分钟。
函数
命名函数创建
- function fn(a,b){ console.log(a+b); } fn(3,4);
- 在当前函数在script标签中创建时,优先放置函数在堆中,函数名放在栈中。
- 当前代码所在script标签上面的script的标签中任意函数和全局变量都是可以调用的,但是其下面script标签中的就不能调用了。
- 函数名:驼峰式命名法,首字母一般小写;如果是构造函数,首字母大写。
- 函数名后的()执行当前函数需要传入的参数。
- { } 里面是函数的语句块,执行函数时该语句块被执行。
- 尽量不要函数嵌套函数。
匿名函数
-
定义匿名函数
var fn = function(){ //代码运行到定义匿名函数这行后才可以调用该匿名函数 } -
自执行函数,定义就执行
执行完,就会立即被销毁。 -
自执行函数的两种形式:
(function(){ console.log(“i am number one”); })(); //W3C推荐下面这一款~ (function(){ console.log(“i am number two”); }()); 包括自执行函数,函数都有执行上下文AO,都要经历预编译。
()为执行符号,只有表达式才能被执行符号执行,函数一旦被执行符号执行,就会忽略函数名。
()也算是数学符号,可以把函数变成表达式,所以(function (){}());这就是自执行函数了。
构造函数 定义函数
- var fn = new Function(“a”,“b”,“console.log(a+b)”); fn(3,5);
- 运行速度缓慢。但灵活。
- 动态构建函数。
作用域
- 函数外定义的变量,函数中可以调用。 函数内定义的变量,不能被函数外部调用。 var 定义变量,如果函数中没有用var定义变量,直接使用该变量,则此变量为全局变量。 window.a的window可以省略,但a还是全局变量 function fn(){a = 10;}此函数内外没有使用var a = 10;所以,a是window下的属性(ES6中是不允许不定义变量就使用)。 在函数中任意位置使用var定义的变量,在该函数的任意位置都认为该变量是局部变量。 有局部变量时,先调用局部变量,没有局部变量才带哦用全局变量。 参数就是局部变量。
var a = 1; //函数外定义的变量a var d = 4; //全局变量 function fn(e) { console.log("a=" + a); //a=1 访问函数外定义的变量a var b = 2; //函数内定义的变量 c = 3; //直接使用该变量,c为全局变量 console.log("d=" + d); //d=undefined,函数任意位置使用var定义了的变量,在次函数中,都认为是局部变量,此时系统认为d未赋值 var d = 44; console.log("d=" + d); //d=44,函数中有局部变量时,先调用局部变量d;没有局部变量,才会像a一样,调用全局变量 console.log("e="+e); //e=6 参数也是局部变量 var e=66; //相当于重新定义了一个局部变量e console.log("e="+e); //e=66 } fn(6); // console.log("b="+b); //报错:b is not defined;说明函数内定义的变量,函数外不能直接访问 console.log("c=" + c); //c=3 c未被定义而直接使用,意味着在直接在window中增加属性,乃window.c,不过是window被省略了
- 补充: 局部变量:函数内用var定义的变量。 全局变量:函数外用var定义的变量;函数内不使用var,直接给变量赋值,相当于给window增加一个属性,此属性也是全局变量。 局部变量 > 全局变量(权重)。 this = window (全局作用域window)。 函数运行完成后,局部变量就会被销毁。
作用域属于一个函数,一个函数产生一个作用域。
[[scope]]:代表作用域。 每个js函数都是一个对象,作用域是不能访问的属性,仅供js引擎存取。 [[scope]]指的是我们所说的作用域,其中存储了运行期上下文的集合。 (运行期上下文AO,一个函数每调用一次,就会产生一个执行期上下文AO,当函数执行完毕,执行期上下文AO就会被销毁)
- 示例
1、判断a、b的作用域 var a = "a=1"; function fn1() { var a = "a=11"; function fn2() { var b = "b=2"; var a = "a=111"; console.log(a); //a=111;可调用自身的变量 } fn2(); // console.log(b); //错误:b is not defined;外部不能调用函数fn2中的变量 } fn1();2、地狱b模式// 函数预先放入堆中;函数b,外部变量b都是全局变量,下面b="b=2"还没有运行,所以在这里全局变量就是函数b,我们把函数b当前参数填入; b(b); //ƒ b(b){console.log(b);var b="b=22";} 打印的是函数b var b="b=2"; //此时外部变量b覆盖函数b,所以此时b不在代表函数b console.log(b); //b=2 function b(b){ console.log(b); var b="b=22"; } b(b); //错误:b is not a function
参数
- 实参与形参一一对应,如果没有对应填入,该形参即为undefined。
function fn(a,b){
console.log(a+b); } fn(3,5);
- 填入参数 == 给参数赋值(相当于)。
- js是弱类型语言,so,参数不能强制约定类型。
- ES5中不允许设置参数的默认值。ES6可以。
function(a,b=3){
console.log(a+b); //就是这种,ES5报错,ES6算出结果 } fn(2);
- 对象作为参数
function fn(obj){ // 相当于给obj赋值一个o,obj和o的引用地址相同 // 当修改obj的属性时,全局的o属性也会被修改 obj.a=10; } var o={ a:1}; fn(o); function fn(obj){ // 重新设置了obj的新的引用地址 obj={ a:3 } } var o={ a:1}; fn(o);
-
如果参数的数量不确定,就不设置参数(ES5);
function getMaxValue(){
console.log(arguments);//可以打印出当前传入的实参,ES5以上版本尽量少用; } getMaxValue(1,2,3,4,5);//Arguments(5) [1, 2, 3, 4, 5, callee: ƒ, Symbol(Symbol.iterator): ƒ]arguments参数集 (有 伪数组 之称);
arguments.callee 函数本身;用于匿名函数,调用自身函数; arguments.callee.caller 调用当前函数的环境函数。示例:没有指定参数个数和大小的情况下,比较大小,选出最大的function getMaxValue(){ //尽量少用if else语句,多些单条件判断语句即可 if(arguments.length===0) return; //如果没有可比较的参数,就不用比了 var max=arguments[0]; //从第一个开始判断 for(var i=0;i
arguments[i]?max:arguments[i]; } console.log("max="+max);}getMaxValue(4,2,5,7,43,0); //max=43 -
临时变量(也是局部变量),临时变量一般用 _variable (下划线开头),一般用在函数参数里。
-
堆栈溢出:递归或者回调的次数过多,没有阻止递归或者回调的条件;要避免这种情况。
回调函数
- 参数调入函数,执行别的函数
1、回调函数-基础 function fn(f){ var a=1; f(a); //以函数为参数,执行 } function fn2(a){ console.log(a+100); } fn(fn2); //1012、用计时器来回调函数 i=0; function callBack(){ console.log("i="+i); i++; } setInterval(callBack,1000); //用计时器每隔1s执行一次;结果是,i从0开始,每1s加1
- 示例:信号灯的变化,功能简单,就三个灯的顺序更迭
function getLight(first,second,third){ first(second,third); } function getRedLight(fn,fn1){ var f=arguments.callee; //被调用者,此处指函数getRedLight var ids=setTimeout(function(){ console.log("red"); clearTimeout(ids); //清除计时器,用一次清一次,以免内存泄漏 fn(fn1,f); //执行回调函数 },1000); //每个1000ms即1s更迭一次 } function getYellowLight(fn,fn1){ var f=arguments.callee; var ids=setTimeout(function(){ console.log("yellow"); clearTimeout(ids); fn(fn1,f); },1000); } function getGreenLight(fn,fn1){ var f=arguments.callee; var ids=setTimeout(function(){ console.log("green"); clearTimeout(ids); fn(fn1,f); },1000); } getLight(getRedLight,getYellowLight,getGreenLight);
递归
- 单函数递归:执行自己
1、调用自己 var i=0; function fn(){ i++; if(i<10) fn(); } fn(); console.log("i="+i);//i=102、匿名函数中调用自身 var j=0; (function(){ j++; if(j<10) arguments.callee(); })(); console.log("j="+j);//j=10
- 双函数递归:arguments.callee与arguments.callee.caller可以完成双函数递归。
var y=0; function fn1(f){ console.log("aaa"); f(); } function fn3(f){ console.log("ccc"); f(); } function fn2(f){ // arguments.callee.caller 当前函数的环境函数,调用当前函数的函数 console.log("bbb"); y++; if(y<10)arguments.callee.caller(arguments.callee); } fn3(fn2); //会不断打印ccc bbb,直到不再满足y<10 //但是耦合度太高,不建议使用
注意:有一“随机块 随机颜色 随机长度 随机排列”的示例在20191228的随堂练习及课后作业有展示,可自行参考。
- 示例:递归在对象中的应用
var obj = { a: 1, b: 1, c: { a: 3, b: 4, c: { a: 5, b: 6, c: { a: 7, b: 8, } } } }1、遍历对象中的元素一般用for in来遍历; 浅复制 var obj1 = { }; for(var prop in obj){ obj1[prop]=obj[prop]; } obj.a=10; //obj1与obj为不同对象 obj.c.a=1000; //obj1与obj中存入属性c对象的引用地址一致,故,一个变,皆变 console.log(obj1,obj);2、用递归来遍历,深复制 function cloneObj(target, source) { for (var prop in source) { //每次将属性为对象的分离出来处理 if (typeof source[prop] === "object" && source[prop] !== null) { target[prop] = { }; cloneObj(target[prop], source[prop]); } else { target[prop] = source[prop]; } } return target; } cloneObj(obj1,obj); obj.a=10; obj.c.a=1000; console.log(obj1,obj); //只有obj里的内容改变,说明此时二者存入的c的引用地址亦不相同了3、同样的属性 使用**引用关系**的方式深度遍历,深复制 function cloneObj(target, source) { for (var prop in source) { if (typeof source[prop] !== "object" || source[prop] === null) { target[prop] = source[prop]; } } // 使用引用关系的方式深度遍历 var o = source.c; target.c = { }; var o1 = target.c; while (o) { for (var prop in o) { if (typeof o[prop] !== "object" || o[prop] === null) { o1[prop] = o[prop]; } } o = o.c; if (o) { o1.c = { }; o1 = o1.c; } } return target } var obj1 = { }; obj1 = cloneObj(obj1, obj); obj.c.c.a = 1000; console.log(obj1,obj); //obj.c.c.a变了,obj1没变
- 二叉树遍历
var obj3={ }; function addValue(obj,left,right){ obj.left={ value:left } obj.right={ value:right } } //依次向二叉树obj3(对象)中添加左右元素 addValue(obj3,1,2); addValue(obj3.left,3,4); addValue(obj3.right,5,6); addValue(obj3.left.left,7,8); addValue(obj3.left.right,9,10); addValue(obj3.right.left,11,12); addValue(obj3.right.right,13,14); console.log(obj3); //{left: {…}, right: {…}} //开始遍历 function mapTree(obj){ if(!obj) return; //直到遍历完,才结束 if(obj.value) console.log(obj.value); //先打印完左边的,再去打印右边的 mapTree(obj.left); mapTree(obj.right); } mapTree(obj3);
函数 - 多态
- 代码的复用性高
- 代码耦合度要尽可能的低
- 代码解耦:减小代码耦合度
return
return的返回值
- 阻断作用
function fn(n){
if(n<5) return; console.log(“aa”); } fn(3);
- 可以允许函数返回一个值,仅一个,但可以用对象、数组返回多个值;
- 返回函数执行的结果,如果函数中没有return,就会返回 undefined。
- return分支返回,典例:输入数字,返回汉字。
var arr=["零","一","二","三","四","五","六","七","八","九"]; // console.log(arr[5]) // var str="123"; // console.log(str[0],str[1],str[2]) // 5 "五"; // 10 "十"; // 15 "十五"; // 20 "二十"; // 36 "三十六"; // 100 "一百"; // 105 "一百零五"; // 110 "一百一十"; // 135 "一百三十五"; // 350 "三百五十"; function getCNNumber(n){ if(n<0 || n>1000) return "错误的消息"; if(n<10) return arr[n]; if(n===10) return "十"; if(n<20) return "十"+arr[String(n)[1]]; if(n>=100 && n%100===0) return arr[String(n)[0]]+"百"; if(n>100 && n%10===0) return arr[String(n)[0]]+"百"+arr[String(n)[1]]+"十"; if(n%10===0) return arr[String(n)[0]]+"十"; if(n<100) return arr[String(n)[0]]+"十"+arr[String(n)[1]]; if(n%100<10) return arr[String(n)[0]]+"百零"+arr[String(n)[2]]; return arr[String(n)[0]]+"百"+arr[String(n)[1]]+"十"+arr[String(n)[2]]; } console.log(getCNNumber(175));
- 返回多个值,通过对象返回;
function fn(w,h){ // var perimeter=(w+h)*2;//一般不是都这么写嘛 // var area=w*h; return { perimeter:(w+h)*2,//其实也可以这么写,以对象的形式输出多个值 area:w*h } } console.log(fn(3,9));
- 如果对象不存在,可以创建一个即o=o||{},不过这种每次执行函数都会创建一个新对象,称这种为工厂模式;单例。
- 每次执行函数创建一个新对象 工厂模式
function fn(){ var o={ }; o.a=10; o.b=20; return o; } console.log(fn()===fn());
- 单例
var o;//console.log(o); //undefinedfunction fn(){ //console.log(o); //{a: 10, b: 20} o=o || { }; //对象o不存在就新建一个,若参数有o,或者在函数中另外新定义了,就无需新建。 o.a=10; o.b=20; return o;}console.log(fn()===fn()); //trueconsole.log(fn()); //{a: 10, b: 20}
- 返回函数体 注意:相关示例请看20191228随堂练习的“函数try”
return break continue 的区别
- return只能使用在函数中;无视任何内容,直接跳出函数。如果函数最后没有返回值,尽量不要写return。 return有时在循环中可以替代break。
function fn(){
for(var i=0;i<10;i++) if(i===5) return; console.log(“a”); } fn();
- break 用于switch或者循环语句中,跳出当前循环或者锚点循环或者switch语句,循环外的语句继续执行。
- continue 只能用在循环语句中,仅跳出当前次循环,继续下一次循环。
计时器
计时器:setInterval setTimeout ;
一般使用他们的两个参数(执行的函数,间隔的时间); 他俩还有第三个参数,可以给相关函数传入数值; setInterval是能够间隔一段时间自动再次执行某函数,直到被清除为止; setTimeout是间隔一段时间后执行,仅执行一次,可以把它放到循环里面; 他俩都能返回一个数值,根据这个数值,分别用clearInterval(ids)与clearTimeout(ids)来清除掉(假设将返回的数值赋值给ids哈);
1、setInterval var i=1; var ids = setInterval(function(){ i++; if(i>5) clearInterval(ids);//仅仅是停掉计时器,程序未结束 console.log("aa",i); },1000); 2、setTimeout var i=1; var dis = setTimeout(function(){ i++; // if(i>5) clearTimeout(dis);//延迟1秒输出i=2,说明,不循环执行 clearTimeout(dis);//清除时间间隔,每次用完一定记得清除 console.log(i); },1000); 3、用计时器实现一个方块从左到右行走 var dists=0,bool=false;//表示出事距离 init(); function init(){ var div = document.getElementById("div0"); div.style.width="100px"; div.style.height="100px"; div.style.backgroundColor="teal"; div.onclick=function(){ bool=!bool; } setInterval(timer,16,div); } function timer(div){ if(!bool) return; dists++; div.style.marginLeft=dists+"px"; }
转载地址:https://blog.csdn.net/weixin_43297321/article/details/104091822 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
网站不错 人气很旺了 加油
[***.192.178.218]2024年04月04日 02时21分51秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
说说 Python 的正则表达式
2019-04-26
说说 Spring Boot 属性配置源的加载顺序
2019-04-26
说说如何查看 Python Django 的版本号
2019-04-26
说说 Python Django 应用的基础目录结构
2019-04-26
说说如何在 Python 的正则表达式中使用分组
2019-04-26
说说 Python 正则表达式的匹配类型
2019-04-26
说说 Python 的贪心和非贪心匹配策略
2019-04-26
说说在 Python 中,如何找出所有字符串匹配
2019-04-26
说说 Python 正则表达式中的那些字符类别码
2019-04-26
说说 Spring Boot 的条件化注解
2019-04-26
说说如何使用 Python 在 word 中创建表格
2019-04-26
Python 基础知识考题与解答(2020 版)
2019-04-26
说说 Oracle 的 SYSDATE 函数
2019-04-26
说说 Oracle 的 NVL 与 NVL2 函数
2019-04-26
说说 TCP 协议以及三次握手流程
2019-04-26
说说 Oracle 的 TRUNC 函数
2019-04-26
系统架构设计笔记(41)—— 系统过渡计划
2019-04-26
系统架构设计笔记(42)—— 软件架构概述
2019-04-26
系统架构设计笔记(57)—— 测试自动化与面向对象的测试
2019-04-26