浅析 JavaScript 中的方法链

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

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

[[381301]]

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.' 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

在数组上也能用方法链:

 

// 在数组上使用方法链的例子 
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 ] 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

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.' 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

方法链是怎样工作的

接下来研究它是怎样工作的。答案很简单,是因为 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: ƒ 
// } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

如果是字符串,则使用的是原始数据类型。但是你所使用的方法例如 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.' 
  • 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.

方法、链、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.' 
  • 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.

这样做的缺点是灵活性不好。如果如果用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: ƒ 
// } 
  • 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.

但是,如果用 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: ƒ 
// } 
  • 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.

如果你一定要用箭头功能,并想要复制对象的话,最好用 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.' 
  • 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.

总结

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

责任编辑:华轩 来源: 前端先锋
相关推荐

2009-07-27 09:29:38

ASP.NET中Jav

2010-09-30 15:19:33

2009-10-12 10:33:11

Javascript替

2009-09-16 16:32:20

JavaScript静

2009-07-17 16:41:48

actionPerfoSwing

2023-04-07 09:07:11

2023-03-09 12:30:55

2023-02-24 14:57:42

区块链元宇宙人工智能

2021-07-27 22:56:00

JavaScript编程开发

2011-05-12 18:26:08

Javascript作用域

2024-08-13 15:23:37

2021-08-10 09:57:27

JavaScriptPromise 前端

2021-04-26 07:51:00

JavaScript方法函数

2016-10-13 19:33:10

javascript数组indexOf

2009-07-06 13:18:35

Servlet方法

2018-02-09 11:08:49

区块链算法主流

2009-09-08 16:22:27

c# listBox

2009-05-21 09:24:42

表空间查询Oracle

2016-09-06 21:37:41

2016-10-19 14:35:20

JavaScript函数式编程
点赞
收藏

51CTO技术栈公众号