javascrpt的函数细节,匿名函数
正常函数:
function a (i,j){ return i+j; }
匿名函数:建议在最外面加上一对圆括号,目的是把函数当成表达式
(function (i,j){ return i + j }) //只完成了定义,没有调用它
匿名函数调用
(function (i,j){ return i + j })(1,2) //那么匿名函数没有函数名,怎么调用呢,后面加上圆括号直接传参调用
匿名函数还可以作为其他对象的函数:
doucument.getElementById("ID").onclick = (function (){ console.log('你点击了我!');});
匿名函数简化写法:箭头函数
(参数) => { return 结果; } 如果只有一个参数,那么()可以省略: 参数1 =>{ return 结果; }
如果函数体内只有一行代码,那么{} 可以省略:
doucument.getElementById("ID").onclick = (参数1) => consle.log('你点击了我!');
javascript中的函数本质上是一个对象,所以可以做赋值操作:
doucument.getElementById("ID").onclick = 函数名或者函数体定义
对象有属性,有方法,可以作为参数传递,可以是另外函数的返回值,非常灵活!
使用 console.dir(函数名),可以看到函数(即对象)内部定义的属性和方法
作为方法参数传递:
function a(){ console.log() } function b(fn){ console.log(); fn(); // 既然fn是从外面传递进来的一个函数对象,那么加上()就可以直接调用它 } b(a);
可以作为函数返回值:
function c(){ console.log("c"); function d(){ console.log("d"); } return d; //返回d的对象定义,并不是返回d的执行结果,所以不会打印d } c()(); //既然返回的是函数定义,那么再加一个()即是调用d函数
函数的作用域:
如果用console.dir(函数名),可以输出函数中的内置属性(js中的函数被当成对象看待),其中用[[....]]双中括号标识的是内置属性,不能调用但是可以查看[[Scopes]]代表的就是该函数的作用域,这里不显示函数体内的作用域,只显示父和全局级的作用域,如下图:closure(a){y:20}就是父作用域,而Global就代表全局作用域,这两个作用域都是函数可以读取的。
函数的闭包:闭包就是指函数可以访问自己的作用域中的变量,即使函数被传递到别的地方,也依然可以访问,因为函数在定义的时候作用域已经确定了,如上所述可以查看作用域,那么下图闭包可以正常打印x,y的值吗?答案是可以。
let和var作用域:
如果函数外层引用的是let变量,那么外层普通的{}也会作为作用域边界,最外层的let 也占一个script作用域
let x=10; if(true){ let y = 20; function(){ console.log(x,y) } console.dir(b); }
如上图:红色框的是自己的作用域,不在讨论之列;
绿框的是Block作用域,界定的关键是{},y=20;
蓝框的是script作用域,x=10
最后黄色框的是Global全局作用域
dir()打印如下图:
如果同样的代码,换成var声明,那么只有Global作用域了,蓝框显示,XY都属于Global作用域,也就是说如果换var声明,那么外层普通的{}不会视为边界
查看该函数作用域,如下图
代码 如下:
// 案例1: var e=10; if(true){ var e=20; //与外面的e视为同一个作用域的同一个变量,20将替代10赋值 console.log(e); //输出20 } console.log(e); //输出20 // 案例2: let e=10; if(true){ //{}被视为作用域边界 let e=20; //用let声明,与外面的e不是同一个变量 console.log(e); //输出20 } console.log(e); //输出10
// 案例3:如果用var要把里、外的作用域分开,那么就需要使用到函数
var e=10;
if(true){
function b(){
var e=20; console.log(e); //输出20
}
b();
}
console.log(e); //输出10
预解析机制:https://www.bilibili.com/video/BV15T411j7pJ/?p=39&vd_source=9752cdd43d8570cd76479220c765bc34
用var声明的变量和用function声明的函数,都会在预编译阶段放到script标签下面,这就是声明提升。(这个跟作用域有关系吗?)
//案例一:将声明的变量提升到script标签下面,因为只是提升了声明的部分到script标签下面,没有赋值值 console.log(myname) //打印undefind var myname ="11" console.log(myname) //打印11 //案例二:赋值型函数 myFunc() //打印错误信息,myFunc不是函数,因为只是提升了声明的部分到script标签下面,没有赋值给他函数的部分,但是如果调用的是一个没有声明的函数,比如func2,那么就会报错此函数未定义,区别就在于预编译阶段是否有找到此函数名 var myFunc = function(){ console.log("11") } myFunc() //打印11 //案例三:声明型函数 test() //不报错,打印11,声明式函数将整个方法体提升到script标签下面,所以在任何地方都可以调用,不一定要在方法定义之后调用 function test(){ console.log("11")} test() //不报错,打印11