Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

链式调用和生成器函数 #49

Open
Wscats opened this issue Jan 10, 2019 · 0 comments
Open

链式调用和生成器函数 #49

Wscats opened this issue Jan 10, 2019 · 0 comments

Comments

@Wscats
Copy link
Owner

Wscats commented Jan 10, 2019

链式调用

如果我们经常使用 jQuery ,我们写代码就会有时候这样写,这种就是我们最常用的链式调用

$(ele).show().find(child).hide()

实现这种链式调用的本质是,方法体内返回对象实例自身 this,让下一个对象的属性能够继续获取该对象的其他属性从而一直驱动着程序

var obj = {
    a: 1,
    func: function () {
        this.a += 1;
        return this
    }
}
obj.func().func();
console.log(Obj.a); // 3

但是如果链式调用中出现异步的函数的时候,我们就要用一个数组来进行集中式管理,类似一个队列的顺序规范,下面的 Queue 类就是一个重要的例子,关键点在于数组this.task = []还有next()的出队列的过程,让每一个函数在链式调用的时候进去数组this.task = []里面缓存起来,然后用用next()不断触发下一个函数的执行,这里面涉及数组的几个常用的方法,比如要置顶到队列前排,类似插队的草最就用unshift(),平时的按正常顺序进队列最后排的就用push(),而从头部出队列执行就用shift()

方法 作用
shift() 删除并返回数组的第一个元素
unshift() 向数组的开头添加一个或更多元素,并返回新的长度
push() 向数组的末尾添加一个或更多元素,并返回新的长度
class Queue {
    constructor() {
        this.task = [];
        setTimeout(() => {
            this.next();
        }, 0)
    }
    next() {
        // 先进先出 队列的过程
        let fn = this.task.shift(); // 删除并返回数组的第一个元素
        fn && fn();
    }
    // 置顶执行
    // 任务队列头部添加,然后执行头部
    first(callback, timer) {
        let fn = () => {
            setTimeout(() => {
                callback();
                this.next();
            }, timer * 1000)
        }
        this.task.unshift(fn); // 向数组的开头添加一个或更多元素,并返回新的长度
        return this;
    }
    // 延时执行
    // 任务队列尾部添加,然后执行头部
    time(callback, timer) {
        let fn = () => {
            setTimeout(() => {
                callback()
                this.next();
            }, timer * 1000)
        }
        this.task.push(fn); // 向数组的末尾添加一个或更多元素,并返回新的长度
        return this;
    }
    // 顺序执行
    // 和延时执行其实一样,只是延时会卡在哪里等待过完再往下走
    // 任务队列尾部添加,然后执行头部
    work(callback) {
        let fn = () => {
            callback();
            this.next();
        }
        this.task.push(fn);
        return this;
    }
}
new Queue()
    .first(() => {
        console.log(0)
    }, 2)
    .first(() => {
        console.log(1)
    }, 2)
    .work(() => {
        console.log(2)
    })
    .time(() => {
        console.log(3)
    }, 1)
// 1 0 2 3
// 两个置顶先执行,谁后置顶谁执行

生成器函数

function* 这种声明方式(function关键字后跟一个星号)会定义一个生成器函数(generator function),它返回一个 Generator 对象

function* fn() {
    console.log(1);
    //暂停!
    yield;
    //调用next方法继续执行
    console.log(2);
}
var iter = fn();
iter.next(); //1
iter.next(); //2

生成器函数在执行时能暂停,后面又能从暂停处继续执行,每 next 一次就执行每个 yield 间隔之间的代码,本质就是动态移动指针

  • 函数生成器特点是函数名前面有一个*
  • 通过调用函数生成一个控制器
  • 调用next()方法开始执行函数
  • 遇到yield函数将暂停
  • 再次调用next()继续执行函数

调用next()方法时,如果传入了参数,那么这个参数会作为上一条执行的yield语句的返回

function *gen(){
    yield 10;
    y=yield 'foo';
    yield y;
}

var gen_obj=gen();
console.log(gen_obj.next());// 执行 yield 10,返回 10
console.log(gen_obj.next());// 执行 yield 'foo',返回 'foo'
console.log(gen_obj.next(10));// 将 10 赋给上一条 yield 'foo' 的左值,即执行 y=10,返回 10
console.log(gen_obj.next());// 执行完毕,value 为 undefined,done 为 true

传递参数

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2; // 4 + 2 
                                  // first =4 是next(4)将参数赋给上一条的
    yield second + 3;             // 5 + 3
}

let iterator = createIterator();
console.log(iterator.next());    // "{ value: 1, done: false }"
console.log(iterator.next(4));   // "{ value: 6, done: false }"
console.log(iterator.next(5));   // "{ value: 8, done: false }"
console.log(iterator.next());    // "{ value: undefined, done: true }"

注意显式返回和生成器函数不能当构造器使用

function* yieldAndReturn() {
  yield "Y";
  return "R";//显式返回处,可以观察到 done 也立即变为了 true
  yield "unreachable";// 不会被执行了
}
var gen = yieldAndReturn()
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }
function* f() {}
var obj = new f; // throws "TypeError: f is not a constructor"
@Wscats Wscats changed the title 链式调用 链式调用和生成器函数 Jan 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant