Skip to content

Static properties and methods #116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
First, let's see why the latter code doesn't work.
Pertama, mari kita lihat mengapa kode terakhir tidak berfungsi.

The reason becomes obvious if we try to run it. An inheriting class constructor must call `super()`. Otherwise `"this"` won't be "defined".
Alasannya menjadi jelas jika kita mencoba menjalankannya. Konstruktor kelas yang mewarisi harus memanggil `super()`. Jika tidak, `"this"` tidak akan "defined".

So here's the fix:
Jadi, inilah perbaikannya:

```js run
class Rabbit extends Object {
constructor(name) {
*!*
super(); // need to call the parent constructor when inheriting
super(); // perlu memanggil konstruktor induk saat mewarisi
*/!*
this.name = name;
}
Expand All @@ -19,63 +19,63 @@ let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // true
```

But that's not all yet.
Tapi itu belum semuanya.

Even after the fix, there's still important difference in `"class Rabbit extends Object"` versus `class Rabbit`.
Bahkan setelah perbaikan, masih ada perbedaan penting dalam `"class Rabbit extends Object"` versus `class Rabbit`.

As we know, the "extends" syntax sets up two prototypes:
Seperti yang kita tahu, sintaks "extends" menyiapkan dua prototipe:

1. Between `"prototype"` of the constructor functions (for methods).
2. Between the constructor functions themselves (for static methods).
1. Antara `"prototype"` dari fungsi konstruktor (untuk metode).
2. Antara konstruktor berfungsi sendiri (untuk metode statis).

In our case, for `class Rabbit extends Object` it means:
Dalam kasus kita, untuk `class Rabbit extends Object` itu berarti:

```js run
class Rabbit extends Object {}

alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) true
alert(Rabbit.prototype.__proto__ === Object.prototype); // (1) true
alert(Rabbit.__proto__ === Object); // (2) true
```

So `Rabbit` now provides access to static methods of `Object` via `Rabbit`, like this:
Jadi `Rabbit` sekarang menyediakan akses ke metode statis `Object` melalui `Rabbit`, seperti ini:

```js run
class Rabbit extends Object {}

*!*
// normally we call Object.getOwnPropertyNames
// biasanya kita sebut Object.getOwnPropertyNames
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
*/!*
```

But if we don't have `extends Object`, then `Rabbit.__proto__` is not set to `Object`.
Tetapi jika kita tidak punya `extends Object`, lalu `Rabbit.__proto__` tidak diatur ke `Object`.

Here's the demo:
Berikut demo nya:

```js run
class Rabbit {}

alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
alert( Rabbit.__proto__ === Function.prototype ); // as any function by default
alert( Rabbit.__proto__ === Function.prototype ); // sebagai fungsi apa pun secara default

*!*
// error, no such function in Rabbit
// error, tidak ada fungsi seperti itu di Rabbit
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
*/!*
```

So `Rabbit` doesn't provide access to static methods of `Object` in that case.
Jadi `Rabbit` tidak menyediakan akses ke metode statis `Object` dalam hal itu.

By the way, `Function.prototype` has "generic" function methods, like `call`, `bind` etc. They are ultimately available in both cases, because for the built-in `Object` constructor, `Object.__proto__ === Function.prototype`.
Ngomong-ngomong, `Function.prototype` mempunyai fungsi metode "generic", seperti `call`, `bind` dll. Mereka terakhir tersedia dalam kedua kasus, karena untuk konstruktor `Object` bawaan, `Object.__proto__ === Function.prototype`.

Here's the picture:
Berikut gambarnya:

![](rabbit-extends-object.svg)

So, to put it short, there are two differences:
Jadi, sederhananya, ada dua perbedaan:

| class Rabbit | class Rabbit extends Object |
|--------------|------------------------------|
| -- | needs to call `super()` in constructor |
| `Rabbit.__proto__ === Function.prototype` | `Rabbit.__proto__ === Object` |
| class Rabbit | class Rabbit extends Object |
| ----------------------------------------- | -------------------------------------- |
| -- | needs to call `super()` in constructor |
| `Rabbit.__proto__ === Function.prototype` | `Rabbit.__proto__ === Object` |
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 3

---

# Class extends Object?
# _Class extends Object?_

As we know, all objects normally inherit from `Object.prototype` and get access to "generic" object methods like `hasOwnProperty` etc.
Seperti yang kita ketahui, semua objek biasanya diwarisi dari `Object.prototype` dan mendapatkan akses ke metode objek "generic" seperti `hasOwnProperty` dll.

For instance:
Misalnya:

```js run
class Rabbit {
Expand All @@ -18,16 +18,16 @@ class Rabbit {
let rabbit = new Rabbit("Rab");

*!*
// hasOwnProperty method is from Object.prototype
// metode hasOwnProperty dari Object.prototype
alert( rabbit.hasOwnProperty('name') ); // true
*/!*
```

But if we spell it out explicitly like `"class Rabbit extends Object"`, then the result would be different from a simple `"class Rabbit"`?
Tapi jika kita mengejanya secara eksplisit seperti `"class Rabbit extends Object"`, maka hasilnya akan berbeda dari `"class Rabbit"`?

What's the difference?
Apa perbedaannya?

Here's an example of such code (it doesn't work -- why? fix it?):
Berikut contoh kodenya (tidak berhasil -- mengapa? memperbaikinya?):

```js
class Rabbit extends Object {
Expand All @@ -36,7 +36,7 @@ class Rabbit extends Object {
}
}

let rabbit = new Rabbit("Rab");
let rabbit = new Rabbit('Rab');

alert( rabbit.hasOwnProperty('name') ); // Error
alert(rabbit.hasOwnProperty('name')); // Error
```
103 changes: 51 additions & 52 deletions 1-js/09-classes/03-static-properties-methods/article.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Properti dan metode statis

# Static properties and methods
Kita juga dapat menetapkan metode ke fungsi kelas itu sendiri, bukan ke `" prototipe "`-nya. Metode seperti itu disebut _static_.

We can also assign a method to the class function itself, not to its `"prototype"`. Such methods are called *static*.

In a class, they are prepended by `static` keyword, like this:
Di dalam kelas, mereka ditambahkan oleh kata kunci `static`, seperti ini:

```js run
class User {
Expand All @@ -17,23 +16,23 @@ class User {
User.staticMethod(); // true
```

That actually does the same as assigning it as a property directly:
Itu sebenarnya sama dengan menetapkannya sebagai properti secara langsung:

```js run
class User { }
class User {}

User.staticMethod = function() {
User.staticMethod = function () {
alert(this === User);
};

User.staticMethod(); // true
```

The value of `this` in `User.staticMethod()` call is the class constructor `User` itself (the "object before dot" rule).
Nilai `this` dalam panggilan `User.staticMethod()` adalah konstruktor kelas `User` itu sendiri (aturan "object before dot").

Usually, static methods are used to implement functions that belong to the class, but not to any particular object of it.
Biasanya, metode statis digunakan untuk mengimplementasikan fungsi yang dimiliki kelas, tetapi tidak untuk objek tertentu darinya.

For instance, we have `Article` objects and need a function to compare them. A natural solution would be to add `Article.compare` method, like this:
Misalnya, kita punya objek `Article` dan membutuhkan sebuah fungsi untuk membandingkan mereka. Solusi natural adalah menambahkan metode `Article.compare`, seperti ini:

```js run
class Article {
Expand All @@ -49,7 +48,7 @@ class Article {
*/!*
}

// usage
// penggunaan
let articles = [
new Article("HTML", new Date(2019, 1, 1)),
new Article("CSS", new Date(2019, 0, 1)),
Expand All @@ -63,17 +62,17 @@ articles.sort(Article.compare);
alert( articles[0].title ); // CSS
```

Here `Article.compare` stands "above" articles, as a means to compare them. It's not a method of an article, but rather of the whole class.
Di sini `Article.compare` berdiri "di atas" _articles_, sebagai alat untuk membandingkannya. Ini bukan metode _article_, melainkan seluruh kelas.

Another example would be a so-called "factory" method. Imagine, we need few ways to create an article:
Contoh lain adalah apa yang disebut metode "factory". Bayangkan, kita butuh beberapa cara untuk membuat _article_:

1. Create by given parameters (`title`, `date` etc).
2. Create an empty article with today's date.
3. ...or else somehow.
1. Buat dengan parameter yang diberikan (`title`, `date` dsb).
2. Buat _article_ kosong dengan tanggal hari ini.
3. ...atau yang lainnya.

The first way can be implemented by the constructor. And for the second one we can make a static method of the class.
Cara pertama dapat diterapkan oleh konstruktor. Dan untuk yang kedua kita bisa membuat metode statis kelas.

Like `Article.createTodays()` here:
Seperti `Article.createTodays()` di sini:

```js run
class Article {
Expand All @@ -84,7 +83,7 @@ class Article {

*!*
static createTodays() {
// remember, this = Article
// ingat, this = Article
return new this("Today's digest", new Date());
}
*/!*
Expand All @@ -95,41 +94,41 @@ let article = Article.createTodays();
alert( article.title ); // Today's digest
```

Now every time we need to create a today's digest, we can call `Article.createTodays()`. Once again, that's not a method of an article, but a method of the whole class.
Sekarang setiap kali kita perlu membuat _today's digest_, kita dapat memanggil `Article.createTodays()`. Sekali lagi, itu bukan metode _article_, tapi metode seluruh kelas.

Static methods are also used in database-related classes to search/save/remove entries from the database, like this:
Metode statis juga digunakan dalam kelas terkait basis data untuk mencari/menyimpan/menghapus entri dari basis data, seperti ini:

```js
// assuming Article is a special class for managing articles
// static method to remove the article:
Article.remove({id: 12345});
// dengan asumsi Article adalah kelas khusus untuk mengelola articles
// metode statis untuk menghapus article:
Article.remove({ id: 12345 });
```

## Static properties
## Properti Statis

[recent browser=Chrome]

Static properties are also possible, they look like regular class properties, but prepended by `static`:
Properti statis juga dimungkinkan, mereka terlihat seperti properti kelas biasa, tetapi diawali dengan `static`:

```js run
class Article {
static publisher = "Ilya Kantor";
static publisher = 'Ilya Kantor';
}

alert( Article.publisher ); // Ilya Kantor
alert(Article.publisher); // Ilya Kantor
```

That is the same as a direct assignment to `Article`:
Itu sama dengan penugasan langsung ke `Article`:

```js
Article.publisher = "Ilya Kantor";
Article.publisher = 'Ilya Kantor';
```

## Inheritance of static properties and methods
## Pewarisan properti dan metode statis

Static properties and methods are inherited.
Properti dan metode statis diwarisi.

For instance, `Animal.compare` and `Animal.planet` in the code below are inherited and accessible as `Rabbit.compare` and `Rabbit.planet`:
Misalnya, `Animal.compare` dan `Animal.planet` dalam kode di bawah ini diwariskan dan dapat diakses sebagai `Rabbit.compare` dan `Rabbit.planet`:

```js run
class Animal {
Expand All @@ -153,7 +152,7 @@ class Animal {

}

// Inherit from Animal
// Mewarisi dari Animal
class Rabbit extends Animal {
hide() {
alert(`${this.name} hides!`);
Expand All @@ -174,43 +173,43 @@ rabbits[0].run(); // Black Rabbit runs with speed 5.
alert(Rabbit.planet); // Earth
```

Now when we call `Rabbit.compare`, the inherited `Animal.compare` will be called.
Sekarang kita dapat memanggil `Rabbit.compare`, yang diwariskan `Animal.compare` akan dipanggil.

How does it work? Again, using prototypes. As you might have already guessed, `extends` gives `Rabbit` the `[[Prototype]]` reference to `Animal`.
Bagaimana cara kerjanya? Sekali lagi, menggunakan prototipe. Seperti yang mungkin sudah kamu duga, `extends` memberi `Rabbit` sebagai `[[Prototype]]` mengacu kepada `Animal`.

![](animal-rabbit-static.svg)

So, `Rabbit extends Animal` creates two `[[Prototype]]` references:
Jadi, `Rabbit extends Animal` membuat dua acuan `[[Prototype]]`:

1. `Rabbit` function prototypally inherits from `Animal` function.
2. `Rabbit.prototype` prototypally inherits from `Animal.prototype`.
1. `Rabbit` fungsi _prototypally_ mewarisi dari fungsi `Animal`.
2. `Rabbit.prototype` _prototypally_ mewarisi dari `Animal.prototype`.

As a result, inheritance works both for regular and static methods.
Hasilnya, pewarisan berfungsi baik untuk metode reguler dan statis.

Here, let's check that by code:
Di sini, mari kita periksa dengan kode:

```js run
class Animal {}
class Rabbit extends Animal {}

// for statics
// untuk statis
alert(Rabbit.__proto__ === Animal); // true

// for regular methods
// untuk metode reguler
alert(Rabbit.prototype.__proto__ === Animal.prototype); // true
```

## Summary
## Ringkasan

Static methods are used for the functionality that belongs to the class "as a whole". It doesn't relate to a concrete class instance.
Metode statis digunakan untuk fungsionalitas yang termasuk dalam kelas "secara keseluruhan". Ini tidak terkait dengan instance kelas konkret.

For example, a method for comparison `Article.compare(article1, article2)` or a factory method `Article.createTodays()`.
Sebagai contoh, metode perbandingan `Article.compare(article1, article2)` atau metode _factory_ `Article.createTodays()`.

They are labeled by the word `static` in class declaration.
Mereka diberi label dengan kata `static` dalam deklarasi kelas.

Static properties are used when we'd like to store class-level data, also not bound to an instance.
Properti statis digunakan ketika kita ingin menyimpan data tingkat kelas, juga tidak terikat pada sebuah _instance_.

The syntax is:
Sintaksnya adalah:

```js
class MyClass {
Expand All @@ -222,13 +221,13 @@ class MyClass {
}
```

Technically, static declaration is the same as assigning to the class itself:
Secara teknis, deklarasi statis sama dengan menetapkan ke kelas itu sendiri:

```js
MyClass.property = ...
MyClass.method = ...
```

Static properties and methods are inherited.
Properti dan metode statis diwarisi.

For `class B extends A` the prototype of the class `B` itself points to `A`: `B.[[Prototype]] = A`. So if a field is not found in `B`, the search continues in `A`.
Untuk `class B extends A` prototipe dari kelas `B` itu sendiri menunjuk ke `A`: `B.[[Prototype]] = A`. Jadi jika bidang tidak ditemukan di `B`, pencarian dilanjutkan di `A`.