一. 函数是一种对象
1. 具名函数
基本语法:
function 函数名(形式参数1,形式参数2,...,形式参数n){
语句
return 返回值
}
2. 匿名函数
基本语法:
let a = function(形式参数1,形式参数2,...,形式参数n){
语句
return 返回值
}
①. 上面的具名函数去掉函数名之后就变成匿名函数
②. let a = 后面的function(形式参数1,形式参数2,...,形式参数n){语句;return 返回值;} 也叫函数表达式
那么请问以下代码能成功执行吗?
let a = function fn(x,y){return x+y}
fn(1,2)
答案 : 不能成功执行!
原因 : 如果这个函数的声明是在等于号右边的,那么fn的作用域就只有等于号右边,出了这个范围fn就不存在.
3. 箭头函数
基本语法:
let 函数名 = (形式参数1,形式参数2,...,形式参数n) => {
语句
return 返回值
}
若返回值为对象时,需要加圆括号! {}会被优先当做代码块! 如:
let fn = (x,y) => ({name:x,age:y})
若形式参数只有一个或语句只有一句时,可以省略圆括号或花括号! 如:
let f1 = x => x*x //形参只有一个且语句只有一句,同时省略了圆括号和花括号
let f2 = (x,y) => x+y //形参有两个,圆括号不可省略
let f3 = (x,y) => {return x+y} //有return,花括号不可省略
4. 构造函数
- 构造函数的主要功能为初始化对象
- 对于任意函数,使用new操作符调用,那么它就是构造函数;不使用new操作符调用,那么它就是普通函数。
- 构造函数名以大写字母开头,普通函数以小写字母开头
- 构造函数调用后会返回一个对象 ,一般不会在构造函数里写return语句
基本语法:
function Person(p_name,p_age){
this.name = p_name
this.age = p_age
} //创建构造函数Person
let p1 = new Person('张三',18) //调用构造函数Person创建新对象p1和p2
let p2 = new Person('李四',20)
二. 函数的执行时机
一个函数的调用(执行)时机不同,那么结果也不同.
函数的执行结果是什么取决于函数在什么时机调用!
函数体本身写在哪跟执行结果无关!!!因为函数要执行了才会有结果!!!
先了解一下定时函数 setTimeout(func,time):
setTimeout(func,time) 是在time(毫秒单位)时间后执行func函数。浏览器引擎按顺序执行程序,遇到setTimeout会将func函数放到执行队列中,等到主程序执行完毕之后,才开始从执行队列(队列中可能有多个待执行的func函数)中按照time延时时间的先后顺序取出来func并执行。即使time=0,也会等主程序运行完之后,才会执行。
再看以下代码:
let i = 0 //注意现在let i = 0在for循环外
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
} //结果为分别打印出6个6
1. 为什么以上代码会打印出6个6 ?
原因:定时函数被加入执行队列,等for循环结束之后,再去调用定时函数。for循环结束之后,i的值已经从0变为6,i等于6之后,六次的定时函数都会共用i=6这个值并打印。所以最终会分别打印6个6。
setTimeout的意思是 : 在把手头上的事忙完了之后(for循环完成之后),再马上做另一件事情(打印出i).可理解成等一会再执行.
那这里为什么不是分别打印出0到5呢? 因为for循环结束之后,才会分别执行6次setTimeout, 且for循环结束之后,i只能等于一个值,即 i = 6 !
2. 怎么修改以上代码可以打印0到5呢 ?
把以上代码的 let i = 0 放到for循环内即可!
即:
for(let i = 0; i<6; i++){ //注意现在let i = 0在for循环内!
setTimeout(()=>{
console.log(i)
},0)
} //结果为分别打印出0,1,2,3,4,5
原因 : JS 在 for 和 let 一起使用的时候会加东西, 每次进入循环时都会把 i 复制一份, console.log(i)里的i变成了不是会变的 i , 即: 当i分别等于0到5时, JS 都会把 i 留在 for 循环这个空间内并复制一个 i , 不跟随新的 i 变化, 所以六次循环一共生成了6个新的 i , 即i被复制了6遍, 并分别通过六次定数函数打印出来. (再加上最开始let i=0这个i, 其实最后总共有7个i)
如果上面的解释还是理解不了, 就记住: 把let放在for循环里就可以做到分别打印出0到5.
3. 还有什么方法能打印出0到5吗 ?
方法:将setTimeout进行封装 ! 改成这样即可:
let i = 0
var f = function(x){
setTimeout(()=>{
console.log(x)
},0)
}
for(i = 0; i<6 ;i++){
f(i)
} //结果为分别打印出 0,1,2,3,4,5
原理:将setTimeout进行封装,此时定时函数的变量作用域就变为f函数代码块内,每次for循环传给定时器的i值都会变为定时函数的私有变量值。