在普通函数中也返回当前实例,我们就可以使用 . 在单行代码中,
一次性连续调用多个方法,就好像它们被链接在一起一样,这就是链式调用,又称链模式
jQuery、Promise 等也使用了链模式
https://www.h5w3.com/29942.html
jquery的链式调用:选择元素,然后从上到下依次进行一系列操作
$('div')
.show()
.addClass('active')
.height('100px')
.css('color', 'red')
.on('click', function(e) {
// ...
})
// 不使用链模式
var divEls = $('div')
divEls.show()
divEls.addClass('active')
divEls.height('100px')
divEls.css('color', 'red')
divEls.on('click', function(e) {
// ...
})
链模式一般会在调用完方法之后返回一个对象,有时则直接返回 this ,
因此又可以继续调用这个对象上的其他方法,这样可以对同一个对象连续执行多个方法
实现链式调用
函数链式调用
让原型方法,都返回该原型的实例对象
所有对象都会继承其原型对象的 prototype上的属性和方法,让原型方法都返回该原型的实例对象,这样就可以对方法进行链式调用
/* 四边形 */
function Rectangle() {
this.length // 长
this.width // 宽
this.color // 颜色
}
/* 设置长度 */
Rectangle.prototype.setLength = function(length) {
this.length = length
return this
}
/* 设置宽度 */
Rectangle.prototype.setWidth = function(width) {
this.width = width
return this
}
/* 设置颜色 */
Rectangle.prototype.setColor = function(color) {
this.color = color
return this
}
var rect = new Rectangle()
.setLength('100px')
.setWidth('80px')
.setColor('blue')
console.log(rect)
// 输出:{length: "100px", width: "80px", color: "blue"}
链式调用练习题
实现一个 human 类,使得他能顺序完成下面的功能
var human = new Human();
human.getUp().cooking().brushing().eat().work();
要求按顺序输出
'getUp'
'cooking'
'teeth brushing 10s 【此处等待 10 秒'】
'eat 5s 【此处等待 5 秒'】
'work'
class Human {
getUp() {
await console.log('getUp')
}
}
class链式调用
让原型方法,都返回该原型的实例对象
/* 四边形 */
class Rectangle {
constructor() {
this.length // 长 undefined
this.width // 宽
this.color // 颜色
}
/* 设置长度 */
setLength(length) {
this.length = length
return this
}
/* 设置宽度 */
setWidth(width) {
this.width = width
return this
}
/* 设置颜色 */
setColor(color) {
this.color = color
return this
}
}
const rect = new Rectangle()
.setLength('100px')
.setWidth('80px')
.setColor('blue')
console.log(rect)
// 输出:{length: "100px", width: "80px", color: "blue"}
const sendmail = () => new Promise(res => setTimeout(res, 1000));
class Mail {
constructor() {
this.mail = 'mail';
}
attachments(files) {
console.log('adding attachments');
return this;
}
async send() {
console.log('sending...');
return sendmail(this.mail);
}
}
(async() => {
console.log('start');
const files = 'files';
await new Mail().attachments(files).send()
console.log('end');
})();
链式不一定必须返回 this
Promise的then返回一个新的 Promise
Promise 的实现中,每次 then 方法返回的就不是 this,而是一个新的 Promise
我们可以不断 then 下去。后面的每一个 then 都不是从最初的 Promise 实例点出来的,
而是从前一个 then 返回的新的 Promise 实例出来的
const prom1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('new promise')
resolve()
}, 500)
})
const prom2 = prom1.then(() => {
console.log('promise then')
})
console.log(prom1 === prom2) // false
$el.end
jquery的方法 end(),将匹配的元素还原为之前一次的状态,返回的也不是 this
返回的之前一次匹配的元素
// 选择所有 p 标签
$("p")
.find("span") // 选择了 p 标签下的 span 标签
.css('color', 'red')
.end() // 返回之前匹配的 p 标签
.css('color', 'blue')
数组的链式调用
因为 filter、map、reduce 这些数组方法返回的仍然是数组,因此可以继续在后面调用数组的方法
- 并不是所有数组方法都返回数组,比如 push 的时候返回的是新数组的 length 属性
[1, 2, 3, 4, 5, 6]
.filter(num => num % 2)
.map(num => num * num)
.reduce((pre, curr) => pre + curr, 0)
jquery的构造函数
var jQuery = function(selector, context) {
// jQuery 方法返回的是 jQuery.fn.init 所 new 出来的对象
// new 出来的 jQuery.fn.init 实例将继承 jQuery.fn 上的方法
return new jQuery.fn.init(selector, context, rootjQuery)
}
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
// jQuery 对象的构造函数
init: function(selector, context, rootjQuery) {
// ... 一顿匹配操作,返回一个拼装好的伪数组的自身实例
// 是 jQuery.fn.init 的实例,也就是我们常用的 jQuery 对象
return this
},
selector: '',
eq: function() { ... },
end: function() { ... },
map: function() { ... },
last: function() { ... },
first: function() { ... },
// ... 其他方法
}
// jQuery.fn.init 的实例都拥有 jQuery.fn 相应的方法
jQuery.fn.init.prototype = jQuery.fn