函数的扩展
与解构赋值默认值结合使用
函数的参数是对象时,需要实参也传递一个对象才能使用默认值
例:
funtion foo({x,y=5}){
console.log(x,y);
}
foo({}) //undefined 5
foo() //TypeError
可以通过对函数的参数对象使用一个空对象作为默认值
例:
function foo({x,y=5} = {}){
console.log(x,y);
}
foo();//undefined 5
如果后面的默认值是一个具体的对象,则实参不可以为空
function m1({x=0,y=0} ={}){
return [x,y];
}
function m2({x,y} = {x:0,y:0}){
return [x,y];
}
console.log(m1());//[0,0]
console.log(m2({}));//[ undefined,undefined]
此时需要传递一个对象,才能进行解构赋值,生成变量x,y
参数默认值的位置
定义默认值的参数,通常情况下时函数的尾参数。这导致了前面参数是不可缺省的。如果需要在前面参数中使用默认值,需要用undefined填充位置。
函数length属性
函数的length属性将返回没有指定默认值的参数个数,遇到第一个指定了默认值的参数时,不再计算后面的参数。
作用域
参数实际执行的是let ,需要注意暂时性死区问题。参数是函数同样需要注意这问题
let命令的暂时性死区
与var的区别是:1.只在声明的块内有效。2.不存在变量提升,所以必须在使用前声明。进入当前作用域时,变量便已存在,但是必须等待声明语句出现,才能获取和使用。
rest参数
箭头函数
例1:
var f = v => v;
第一个v是参数,第二个是返回值
多个参数或无参数 使用();代码块部分多余一条语句,使用大括号括起,return语句返回。如果没有返回值且只有一行语句,void doesNotReturn();
此函数中的this对象是定义时所在的对象,即是固定的。
函数
函数的声明
1.function *name*(*参数*){}
2.var *name*=function *可选_name*(*参数*){};变量赋值,可选name只能在函数内部使用。
3.var *name*=Function();
例:
var add= new Function(
'x',
'y',
'return x+y'
);
只有最后一个被作为函数体,其他的都是参数
4.函数被多次声明,以最后一次为准,因为函数声明会提升。
函数是一种值
函数被看作一种值,因而与(数值、字符串)等地位相同。凡是可以用值得,就可以用函数。
函数声明和变量声明一样都会被提升到代码头部。
函数的属性方法
name返回函数的名字,需要注意的是
对于使用变量赋值定义的且是具名函数,返回的是该名字,但是不能在函数外部使用。
toString()f返回一个字符串,内容是函数的源码
函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域。
例:
var a = 1;
var x = function () {
console.log(a);
};
function f() {
var a = 2;
x();
}
f() // 1
函数x不会引用函数f的内部变量
传递方式
参数类型如果是原始类型(数值、字符串、布尔值),传递方式是传值传递;如果是复合类型,则是
传址传递
函数闭包
只有函内部得子函数才能读取内部变量,闭包可以使得内部比哪里记住上次调用时的运算结果。闭包的另一作用是封装对象的私有属性和私有方法。滥用闭包有性能问题。
未完待续:箭头函数
异步操作
只有当前提事件完成,才会进入主线程执行;未完成则在任务队列
任务队列和事件循环
主线程先取执行所有同步任务,等到同步任务全部执行完成,便会去任务队列中查看是否有满足条件的异步任务,若满足则重新进入主线程执行。
异步操作的模式
1.回调函数:把f2写成f1的回调函数,保证执行完f1再执行f2
function f1(callback){
console.log("f1");
callback();
}
function f2(){
console.log("f2");
}
f1(f2);
2.事件监听:异步任务的执行取决与某个事件是否发生
3.串行执行
var items = [1,2,3,4,5,6];
var results = [];
function async(arg,callback){
console.log('参数为'+arg+',1秒后返回结果');
setTimeout(function () {callback(arg*2);},1000);
}
function final(value){
console.log('完成:',value);
}
function series(item){
if(item){
async(item,function(result){
results.push(result);
return series(items.shift());
});
}else{
return final(results[results.length-1]);
}
}
series(items.shift());
4.并行执行
var items = [1,2,3,4,5,6];
var results = [];
function async(arg,callback){
console.log('参数为'+arg+',1秒后返回结果');
setTimeout(function () {callback(arg*2);},1000);
}
function final(value){
console.log('完成:',value);
}
items.forEach(function(item){
async(item,function(result){
results.push(result);
if(results.length === items.length){
final(results[results.length-1]);
}
})
})
5.并串行结合
定时器
主要是采用setTimeout()和setInterval()两个函数向任务队列添加定时任务
setTimeout()
1.指定一个函数或代码段在多少毫秒之后执行,返回一个整数表示的时期的编号
2.var timeId = setTimeout(func|code,delay);第二个参数省略默认为0.还允许有更多参数,将被依此传入回调函数
3.如果回调函数是对象的方法,那么setTimeout使得方法内部的this 关键字指向全局环境,而不是定义时所在的那个对象.可以使用将该方法绑定在obj上。
setInterval()
用法与setTimeout完全一致,区别时setInterval 指定某个任务每隔一段时间就执行一次。
间隔时间是包括执行时间的,如果需要两次执行之间有固定的间隔,可以使用setTimeout指定
var i = 1;
var timer = setTimeout(function f() {
// ...
timer = setTimeout(f, 2000);
}, 2000);
同步函数执行完成才会执行setTimeout setInterval指定的回调函数,这使得其不一定会按照预定时间执行。
Promise 对象
含义
1.Promise 是一个对象,从它可以获取异步操作处于什么状态,pending(进行中),fulfilled(已成功),rejected(已失败)。
2.Promise 的状态只被该异步操作决定,不可修改和中止
Promise构造函数
var promise = new Promise(function (resolve, reject) {
// ...
if (/* 异步操作成功 */){
resolve(value);
} else { /* 异步操作失败 */
reject(new Error());
}
});
resolve的作用是将其状态从“未完成”到“成功”,而reject则是失败。
then方法
用于添加回调函数
var p1 = new Promise(function(resolve,reject){
resolve('success');
});
p1.then(console.log,console.error);
1.then方法可以接受两个回调函数,第一个是成功的回调函数,第二个是失败的。
2.then方法可以链式使用的,因为then方法返回的是一个新的Proise实例
3.Promise的回调函数是异步任务,会在同步任务之后执行
new Promise(function(resolve,reject){
resolve(1);
}).then(console.log);
console.log(2);