写文章为了让自己好记住知识点,也为了后续当作笔记来看待

前言

之前有过一次面试,面试官问 promise 相关的知识点,然后我回答了,他追问说 promise 的链式怎么实现?我当时没反应过来。面试官很有耐心,说 jquery 也是有链式的,你看过 jquery 的源码吗?它的链式怎么写的?我还是不知道,后来没通过面试,这个知识点常被我回忆,现在正好有时间,来写一写

正文

答案是:返回this

先来一个例子:

1
2
3
4
5
6
7
8
9
10
var person = {
name: 'johan',
age: 28,
sayName: function() {
console.log('my name is' + this.name)
},
sayAge: function() {
console.log('my age is ' + this.age)
}
}

命名一个对象,它有两个方法,sayName 和 sayAge ,如果我想这样表示 person.sayName().sayAge() 呢?怎么做,在方法 sayName 和 sayAge 中返回 this,即

1
2
3
4
5
6
7
8
9
10
11
12
var person = {
name: 'johan',
age: 28,
sayName: function() {
console.log('my name is' + this.name)
return this;
},
sayAge: function() {
console.log('my age is ' + this.age)
return this;
}
}

这就是表示,调用方法 sayName 、sayAge 后,返回调用者,即例子 person.sayName() ,person 调用 sayName,调用完后返回值还是 person。所以它可以继续链式调用 sayAge,因为它表示的还是 person

Promise 中的链式

Promise 本身没有链式,但是 Promise 的实例对象中的 then 有链式

1
2
3
4
5
6
7
8
9
function MyPromise(executor) {

}

MyPromise.prototype.then = function (onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
...
})
}

当你使用 Promise 时,一般是这样使用:

1
2
3
4
5
6
let promise = new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
})
promise.then(() => {
console.log('1s后显示')
})

如果加上链式

1
2
3
4
5
promise.then(() => {
console.log('1s后显示,第一个')
}).then(() => {
console.log('1s后显示,第二个')
})

所以很明显,每调用一次 then,就是返回一个实例对象(return new Promise

Jquery 中的链式

源码太多内容,就拿 core.js 中的代码为例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
jQuery.fn = jQuery.prototype = {

// The current version of jQuery being used
jquery: version,

constructor: jQuery,

// The default length of a jQuery object is 0
length: 0,

toArray: function() {
return slice.call( this );
},

// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function( num ) {

// Return all the elements in a clean array
if ( num == null ) {
return slice.call( this );
}

// Return just the one element from the set
return num < 0 ? this[ num + this.length ] : this[ num ];
},

// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function( elems ) {

// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );

// Add the old object onto the stack (as a reference)
ret.prevObject = this;

// Return the newly-formed element set
return ret;
},

// Execute a callback for every element in the matched set.
each: function( callback ) {
return jQuery.each( this, callback );
},

map: function( callback ) {
return this.pushStack( jQuery.map( this, function( elem, i ) {
return callback.call( elem, i, elem );
} ) );
},

slice: function() {
return this.pushStack( slice.apply( this, arguments ) );
},

first: function() {
return this.eq( 0 );
},

last: function() {
return this.eq( -1 );
},

even: function() {
return this.pushStack( jQuery.grep( this, function( _elem, i ) {
return ( i + 1 ) % 2;
} ) );
},

odd: function() {
return this.pushStack( jQuery.grep( this, function( _elem, i ) {
return i % 2;
} ) );
},

eq: function( i ) {
var len = this.length,
j = +i + ( i < 0 ? len : 0 );
return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
},

end: function() {
return this.prevObject || this.constructor();
}
};

我们不用看全部,但看其中的方法,是不是和最开始的例子很像——return this

所以链式不可怕,可怕的是,动都不动就自我劝退