浅析 JavaScript 中的方法链

更新日期: 2021-02-01阅读: 2.2k标签: 方法

方法链是一种流行的编程方法,可以帮助你写出更简洁易读的代码。在本文中我们一起学习 JavaScript 中的方法链是什么,以及它是怎样工作的。另外我们还会探讨如何使用方法链接来提高代码的质量和可读性。


JavaScript 中方法链

你一定曾经用过 jquery 之类的库,可能看到过类似的东西。在进行级联时主要有两种方法:一种是一个接一个的执行方法,另一种是在同一行上。在纯 JavaScript 中这种做法也很普遍。你可以在数组、字符串和 promise 看到它。

在这些情况下所有的过程都是相同的。首先引用要使用的对象。然后根据需要使用多种方法。但不是单独使用这些方法,而要一个接一个地使用。基本上是把它们链接在一起。先看一些例子。


方法链的例子

在处理字符串时有两种方法。第一个种不用方法链,这要求必须在字符串上分别使用每个方法,这样必须每次都引用这个字符串。

第二种方式是用方法链。这时可以用所有想要的字符串方法。写出的代码也可以是单行或多行,这取决于你的习惯。而且只需要引用一次字符串。尽管结果相同,但是代码量却有很大的差异。

// 在字符串上使用方法链的例子
let myStr = ' - Hello-world. '

// 不用方法链:
myStr = myStr.toLowerCase()
myStr = myStr.replace(/-/g, ' ')
myStr = myStr.trim()

// 用方法链:
myStr = myStr.toLowerCase().replace(/-/g, ' ').trim()

// 多行方法链的写法:
myStr = myStr
.toLowerCase()
.replace(/-/g, ' ')
.trim()

// 查看 "myStr" 的值
console.log(myStr)
// Output:
// 'hello world.'

在数组上也能用方法链:

// 在数组上使用方法链的例子
let myArray = [1, 7, 3, null, 8, null, 0, null, '20', 15]

// 不用方法链:
myArray = myArray.filter(el => typeof el === 'number' && isFinite(el))
myArray = myArray.sort((x, y) => x - y)

// 使用方法链:
myArray = myArray.filter(el => typeof el === 'number' && isFinite(el)).sort((x, y) => x - y)

// 多行方法链的写法:
myArray = myArray
.filter(el => typeof el === 'number' && isFinite(el))
.sort((x, y) => x - y)

// 查看 "myArray" 的值.
console.log(myArray)
// Output:
// [ 0, 1, 3, 7, 8 ]

Promise 是一个很好的例子,因为在使用时差不多全都是方法链。首先创建一个 promise,然后添加适当的处理函数

// 创建 Promise
const myPromise = new Promise((resolve, reject) => {
// 创建一个假延迟
setTimeout(function() {
// 用一条简单的消息解决诺言 promise
resolve('Sorry, no data.')
}, 1000)
})

// 使用方法链:
myPromise.then((data) => console.log(data)).catch(err => console.log(error))

// 多行方法链的写法:
myPromise
.then((data) => console.log(data))
.catch(err => console.log(error))
// Output:
// 'Sorry, no data.'


方法链是怎样工作的

接下来研究它是怎样工作的。答案很简单,是因为 this 。

假设有一个对象。如果在该对象内使用 this ,它会引用这个对象。如果创建该对象的实例或副本,则 this 将会引用这个实例或副本。当你使用某些字符串或数组方法时,实际上是在用一个对象。

const myObj = {
name: 'Stuart',
age: 65,
sayHi() {
// 这里的 this 是 myObj 的引用
return `Hi my name is ${this.name}.`
},
logMe() {
console.log(this)
}
}

myObj.sayHi()
// Output:
// 'Hi my name is Stuart.'

myObj.logMe()
// Output:
// {
// name: 'Stuart',
// age: 65,
// sayHi: ƒ,
// logMe: ƒ
// }

如果是字符串,则使用的是原始数据类型。但是你所使用的方法例如 toLowerCase() ,存在于 String 对象的原型中。在对象上使用方法链还有一个关键要素: this 。

为了使链起作用,方法必须返回与其一起使用的对象,也就是必须返回 this 。就像接力赛跑时的接力棒一样。


在 JavaScript 中实现方法链

为了使方法链有效,必须满足三个条件:首先,需要一些对象。其次,该对象需要一些以后可以调用的方法。第三,这些方法必须返回对象本身,它们必须返回 this 才能使用方法链。

让我们创建一个简单的对象 person 。 person 有 name , age 和 state 属性。 state 用来表示当前处于什么状态。要想改变这个状态,需要用到几个方法: walk() , sleep() , eat() , drink() , work() 和 exercise() 。

由于我们希望所有这些方法都是可链的,所以它们都必须返回 this 。另外代码中还有一个用来把当前状态记录到控制台的工具方法。

// 创建 person 对象
const person = {
name: 'Jack Doer',
age: 41,
state: null,
logState() {
console.log(this.state)
},
drink() {
// 修改 person 的 state.
this.state = 'Drinking.'

// 把状态输出到控制台
this.logState()

// 返回 this 值。
return this
},
eat() {
this.state = 'Eating.'
this.logState()
return this
},
exercise() {
this.state = 'Exercising.'
this.logState()
return this
},
sleep() {
this.state = 'Sleeping.'
this.logState()
return this
},
walk() {
this.state = 'Walking.'
this.logState()
return this
},
work() {
this.state = 'Working.'
this.logState()
return this
}
}

//
person
.drink() // Output: 'Drinking.'
.exercise() // Output: 'Exercising.'
.eat() // Output: 'Eating.'
.work() // Output: 'Working.'
.walk() // Output: 'Walking.'
.sleep() // Output: 'Sleeping.'

// 写在一行上
person.drink().exercise().eat().work().walk().sleep()
// Output:
// 'Drinking.'
// 'Exercising.'
// 'Eating.'
// 'Working.'
// 'Walking.'
// 'Sleeping.'


方法、链、this 和箭头函数

必须使用 this 也意味着无法使用箭头函数创建方法链。因为在箭头函数中, this 没有绑定到对象的实例,而是全局对象 window 的引用。如果返回 this ,那么返回的不是对象本身而是 window 。

另一个问题是从箭头函数内部访问和修改对象属性。由于 this 是全局对象 window ,所以不能用它来引用对象及其属性。

如果你一定要使用箭头函数,必须想办法绕过这种方法。不用 this 来引用该对象,必须直接通过其名称引用该对象,也就是用对象名替换所有出现在箭头功能内的 this 。

// 创建 person 对象
const person = {
name: 'Jack Doer',
age: 41,
state: null,
logState() {
console.log(this.state)
},
drink: () => {
person.state = 'Drinking.'

person.logState()

return person
},
eat: () => {
person.state = 'Eating.'

person.logState()

return person
},
exercise: () => {
person.state = 'Exercising.'

person.logState()

return person
},
sleep: () => {
person.state = 'Sleeping.'

person.logState()

return person
},
walk: () => {
person.state = 'Walking.'

person.logState()

return person
},
work: () => {
person.state = 'Working.'

person.logState()

return person
}
}

//
person
.drink() // Output: 'Drinking.'
.exercise() // Output: 'Exercising.'
.eat() // Output: 'Eating.'
.work() // Output: 'Working.'
.walk() // Output: 'Walking.'
.sleep() // Output: 'Sleeping.'

这样做的缺点是灵活性不好。如果如果用Object.assign() 和 Object.create()复制对象,所有箭头函数仍然会硬连接到原始对象。

// 创建原始 person 对象
const person = {
name: 'Jack Doer',
age: 41,
state: null,
logState() {
// 打印整个对象
console.log(this)
},
drink: () => {
person.state = 'Drinking.'

person.logState()

return person
},
eat: () => {
person.state = 'Eating.'

person.logState()

return person
}
}

// 让 person eat
person.eat()
// Output:
// {
// name: 'Jack Doer',
// age: 41,
// state: 'Eating.',
// logState: ƒ,
// drink: ƒ,
// eat: ƒ
// }

// 基于person对象创建新对象。
const newPerson = new Object(person)

// 修改 "name" 和 "age" 属性
newPerson.name = 'Jackie Holmes'
newPerson.age = 33

// 让 newPerson drink。
// 这会打印 Jack Doer 而不是 Jackie Holmes。
newPerson.drink()
// Output:
// {
// name: 'Jack Doer',
// age: 41,
// state: 'Drinking.',
// logState: ƒ,
// drink: ƒ,
// eat: ƒ
// }

但是,如果用  Object()  构造函数,就不会发生上述问题。如果用 new 关键字的和 Object() 构造造函数,将会创建独立的新对象。当你对这个新对象使用某个方法时,它将仅对这个新对象有效,而对原始对象无效。

// 创建原始 person 对象
const person = {
name: 'Jack Doer',
age: 41,
state: null,
logState() {
// 打印整个对象
console.log(this)
},
drink: () => {
person.state = 'Drinking.'

person.logState()

return person
},
eat: () => {
person.state = 'Eating.'

person.logState()

return person
}
}

// 让 person eat.
person.eat()
// Output:
// {
// name: 'Jack Doer',
// age: 41,
// state: 'Eating.',
// logState: ƒ,
// drink: ƒ,
// eat: ƒ
// }

// 基于 person 对象创建新对象
const newPerson = new Object(person)

// 修改 "name" 和 "age" 属性
newPerson.name = 'Jackie Holmes'
newPerson.age = 33

// 让 newPerson drink.
newPerson.drink()
// Output:
// {
// name: 'Jackie Holmes',
// age: 33,
// state: 'Drinking.',
// logState: ƒ,
// drink: ƒ,
// eat: ƒ
// }

如果你一定要用箭头功能,并想要复制对象的话,最好用 Object() 构造函数和 new 关键字创建这些副本。否则只需要用常规函数就够了。


方法链和类

如果你喜欢使用 JavaScript 类,也可以在JavaScript中使用方法链接。除了语法略又不同外,整个过程和对象是一样的。但是要注意所有可链的方法都必须返回 this 。

// 创建 Person 类
class Person {
constructor(name, age) {
this.name = name
this.age = age
this.state = null
}

logState() {
console.log(this.state)
}

drink() {
this.state = 'Drinking.'

this.logState()

return this
}

eat() {
this.state = 'Eating.'

this.logState()

return this
}

sleep() {
this.state = 'Sleeping.'

this.logState()

return this
}
}

// 创建 Person 类的实例
const joe = new Person('Joe', 55)

// 使用方法链
joe
.drink() // Output: 'Drinking.'
.eat() // Output: 'Eating.'
.sleep() // Output: 'Sleeping.'

方法链是非常有用的,它可以帮你编写更短、更易读的代码。

来自:https://view.inews.qq.com/a/20210207A0A8GA00


链接: https://fly63.com/article/detial/10156

html/css解决inline-block内联元素间隙的多种方法总汇

inline-blcok元素中间的空白符引起的间隙,处理方法总结包括:改变书写结构、使用font-size:0、使用margin负值、使用letter-spacing或word-spacing、丢失结束标签、W3C推荐 导航方法(兼容IE6等)、YUI的inline-block间隙处理等...

JS实现碰撞检测的方法分析

本文实例讲述了JS实现碰撞检测的方法。分享给大家供大家参考,具体如下:一个简单的碰撞检测例子,检测div1是否和div2发生碰撞,当div1碰到div2时,改变div2的颜色

css实现左右两边竖条的多种方法总结

css实现边竖条的多种方式:border、使用伪元素、外 box-shadow、内 box-shadow、drop-shadow、渐变 linearGradient、轮廓 outline、滚动条

js中math方法_整理js中常用的math方法总结

记录下与Math有关的常用方法,如:求最大值、最小值等,或者是保留几位数啥的。本文主要介绍了JavaScript中Math对象的方法,具有一定的参考价值,下面跟着小编一起来看下吧

js中split,splice,slice方法之间的差异_splice()、slice()、split()函数的区分

Split是切割字符串的一种方法,该方法主要用于把一个字符串分割成字符串数组。splice()方法向/从数组中添加/删除元素,然后返回被删除的元素组成的数组。slice()方法主要用于截取数组,并返回截取到的新数组。

JS获取当前时间戳的方法

第一种:获取的时间戳是把毫秒改成000显示,因为这种方式只精确到秒,第二种和第三种是获取了当前毫秒的时间戳。

js 实现二级联动

在web开发中我们经常会遇到页面的一个二级联动技术,二级联动字面解释就是说我在选择一级select不同的option,下面的二级option的属性值在进行相应的变化。

常用原生JS方法总结(兼容性写法)

经常会用到原生JS来写前端。。。但是原生JS的一些方法在适应各个浏览器的时候写法有的也不怎么一样的,一下的方法都是包裹在一个EventUtil对象里面的,直接采用对象字面量定义方法了

js 操作剪贴板

是通过 js 操作 textarea input 输入框,只能操作输入框,不能操作其它元素。所有的 复制/剪切/粘贴 都是要在选中输入框中的文本之后,才进行操作的。

js async的常用方法

async函数是Generator 函数的语法糖,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。async函数对Generator 函数的改进点有以下几点:

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!