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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:js 对象
下一篇:PC端页面布局 - 元素在父元素里上下左右居中

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年04月04日 02时21分51秒