每天推薦一個 GitHub 優質開源項目和一篇精選英文科技或編程文章原文,歡迎關注開源日報。交流QQ群:202790710;微博:https://weibo.com/openingsource;電報群 https://t.me/OpeningSourceOrg


今日推薦開源項目:《Python 二連 Douyin-Bot》GitHub鏈接

推薦理由:還在刷抖音找不到漂亮小姐姐?沒關係,Python 二連幫你解決這個問題。這個項目就是利用 Python 寫出的尋找漂亮小姐姐的程序,不過人臉識別的 API 是管別的地方請求要來的。有了這個,你就不需要再花好幾個小時去在抖音上尋找漂亮小姐姐了


今日推薦英文原文:《Function Borrowing in JavaScript》作者:Betsy Sallee

原文鏈接:https://medium.com/@ensallee/function-borrowing-in-javascript-4bd671e9d7b4

推薦理由:如果你需要使用別的類裡面的某個函數,繼承就顯得太麻煩了,因為你只是用一個函數而不是需要幹什麼更多的事情,這個時候函數借用興許能幫你一把。

Function Borrowing in JavaScript

When we create JavaScript objects, we typically associate them with certain behavior. Consider the below example:

class Dog {
  constructor(name, age, breed) {
    this.name = name
    this.age = age
    this.breed = breed
  }
  tellUsAboutYourSelf() {
    return `My name is ${this.name}. I am a ${this.breed} and I am ${this.age} years old.`
  }

  woof() {
    return "WOOF!!!"
  }
}

let fido = new Dog("Fido", 3, "dachshund")
fido.tellUsAboutYourSelf()
//=> 'My name is Fido. I am a dachshund and I am 3 years old.'

We』ve created a class Dog with three properties and two methods, one of which is tellUsAboutYourSelf(). We』ve also created a new instance of Dog, which is saved into the variable fido. Pretty straightforward. Now, let』s create another class and instantiate a new instance:

class Cat {
  constructor(name, age, breed) {
    this.name = name
    this.age = age
    this.breed = breed
  }

  meow() {
    return "MEOW!!!"
  }
}

let sparkles = new Cat("Sparkles", 5, "Siamese")
sparkles.tellUsAboutYourSelf()
//=>TypeError: sparkles.tellUsAboutYourSelf is not a function

We』ve created a Cat object with the same properties as our Dog object, but our instance of Cat, which is saved into the variable sparkles, isn』t able to tell us about itself. We could refactor our code so that the class Cat inherits from the class Dog, but in that scenario, all of our Cat objects would be able to 「woof,」 which doesn』t seem appropriate or necessary. Enter: function borrowing.

How does it work?

Function borrowing allows us to use the methods of one object on a different object without having to make a copy of that method and maintain it in two separate places. It is accomplished through the use of .call().apply(), or .bind(), all of which exist to explicitly set this on the method we are borrowing.

Given the objects we created above, take a look at function borrowing in action:

fido.tellUsAboutYourSelf.call(sparkles)

//=>』My name is Sparkles. I am a Siamese and I am 5 years old.』

fido.tellUsAboutYourSelf.apply(sparkles)

//=>』My name is Sparkles. I am a Siamese and I am 5 years old.』

const describeSparkles = fido.tellUsAboutYourSelf.bind(sparkles)

describeSparkles()

//=>』My name is Sparkles. I am a Siamese and I am 5 years old.』

Each of these examples work because this, when referenced inside a method, refers to the object that received the method call. .call().apply(), and .bind() work by allowing us to alter the object to which this refers inside of the .tellUsAboutYourSelf() method. Whereas .call() and .apply() immediately execute the function call, .bind() saves the function for later. Once we』ve saved the borrowed function into the variable describeSparkles, we can call invoke describeSparkles one hundred lines later and still see the same output.

What』s the point?

The central benefit of function borrowing is that it allows you to forego inheritance. There』s no reason for you to force a class to inherit from another if you』re only doing so in order to grant instances of the child class access to a single method. And as I mentioned above, function borrowing keeps you from having to write the same function twice and maintain it in two places, which reduces the risk of bugs.

The most important practical application of function borrowing pertains to native methods, and specifically, to Array.prototype.slice. There are several list-like data structures that aren』t arrays, and it』s useful to be able to treat them as arrays and operate on them as such. One of the most prevalent list-like data structures that isn』t an array is arguments. The arguments object represents all the parameters passed in to a given (non-arrow) function.

Take, for example, the below function:

function findO() {
  var args = Array.prototype.slice.call(arguments)
  return args.filter(a => a.includes('o'))
}

findO("orchid", "tulip", "rose", "lilac")
=> [ 'orchid', 'rose' ]

In the above example, findO is a variadic function, which means it takes a variable number of arguments. We』ve passed it four strings, and we』d like to see which of those strings contain the letter 『o』. The arguments object holds those four strings, but we can』t simply call .filter() on arguments because it is not an array. We』re able to convert it into an array, however, by borrowing the .slice method from Array.prototype, and setting this to equal the arguments object. Once it has been converted to an array, we have access to all of the built-in methods on Array.

Nifty!


每天推薦一個 GitHub 優質開源項目和一篇精選英文科技或編程文章原文,歡迎關注開源日報。交流QQ群:202790710;微博:https://weibo.com/openingsource;電報群 https://t.me/OpeningSourceOrg