在普通函数中也返回当前实例,我们就可以使用 . 在单行代码中,
一次性连续调用多个方法,就好像它们被链接在一起一样,这就是链式调用,又称链模式
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 = lengthreturn this}/* 设置宽度 */Rectangle.prototype.setWidth = function(width) {this.width = widthreturn this}/* 设置颜色 */Rectangle.prototype.setColor = function(color) {this.color = colorreturn 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 // 长 undefinedthis.width // 宽this.color // 颜色}/* 设置长度 */setLength(length) {this.length = lengthreturn this}/* 设置宽度 */setWidth(width) {this.width = widthreturn this}/* 设置颜色 */setColor(color) {this.color = colorreturn 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
