JavaScript的学习之路(2)

169 阅读6分钟

函数的扩展

与解构赋值默认值结合使用

函数的参数是对象时,需要实参也传递一个对象才能使用默认值

例:
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);

注意的是Promise的回调函数其实属于微任务,他们会追加到本轮事件循环,而不是一般任务追加到下一轮。

all()

Promise.all()方法用于将多个Promise实例,包装成一个新的Promise实例。const p = Promise.all([p1,p2,p3]);

p的状态由(promise 实例)p1、p2、p3决定,分成两种情况。(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。