# Why is extending built-in JavaScript objects not a good idea?
題目給的答案
```
擴展原生的JS物件,表示在其原生物件的prototype裡加上屬性或者方法。
想像你使用了不少函式庫,而這些函式庫都有一個名為contains的方法,
由於名稱同樣的關係,會使得方法被彼此覆蓋。
建議唯一擴展原生物件的時機:polyfill(讓舊版瀏覽器可以使用JS API的各種庫)
```
emm...
---
JS本身提供了很多object,這些物件或方法給予很多基本應用的便利性,例如map、slice、Date等,但越往後發展,你可能發現你想要達到的目標遠比這些基本應用還要多。
看個栗子🌰
```
function shuffle(input) {
for (let i = input.length - 1; i >= 0; i--) {
let randomIndex = Math.floor(Math.random() * (i + 1));
let itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
return input;
}
```
shuffle函式提供了,將陣列裡的值重新打亂排列的功能。
如果我們要調用該函式,通常的做法是
```
let shuffleArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
shuffle(shuffleArray);
```
那摸,大膽的想法來了,我們能將其變成陣列內建的函式,就像我們在調用array.map()一樣去調用shuffleArray.shuffle()呢?
這裡我們將會用到原型的觀念!
所以我們坐上時光機,回想一下關於prototype的一些概念
```javascript=
// 定義一個陣列
let tempArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
```
* tempArray由於是陣列,因此繼承了Array.prototype的方法
* Array也是物件,所以Array.prototype繼承Object.prototype的方法
* Array.prototype裡的constructor提供幾個built-in的方法
* !!! 為了將我們自製的shuffle函式成為built-in的一員,我們必須在Array.prototype裡新增該函式

(image by [here](https://www.kirupa.com/html5/extending_built_in_objects_javascript.htm))
```javascript=
// 增加shuffle
Array.prototype.shuffle = function () {
let input = this;
for (let i = input.length - 1; i >= 0; i--) {
let randomIndex = Math.floor(Math.random() * (i + 1));
let itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
return input;
}
// 這時就可以調用了
shuffleArray.shuffle();
```
因為shuffle已經成為Array.prototype的built-in之一
這也是由於原型繼承的工作特性,才能有這種效果

---
#### 理解了何謂built-in object extend後,我們要探討的是至今仍有爭議的
### 「為什麼不該extend built-in object?」
1. 從上面的例子我們可以看到,利用prototype來操作這件事情有多麽容易
```javascript=
// 打破原方法的例子
Array.prototype.slice = function () {
let input = this;
input[0] = "This is an awesome example!";
return input;
}
let tempArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
tempArray.slice();
alert(tempArray);
```
2. 不能保證未來JS built-in的改動,是否可能跟你的代碼擁有一樣的function,如果很不幸的一樣,你的code可能就會崩壞哦。例如,有使用到for ... in的話,肯定先crush,尤其你無法保證第三方庫會用到哪些method
```javascript=
Array.prototype.foo = 1;
var a = [1,2,3,4,5];
for (let x in a){
console.log(x)
}
```
tips - for in的問題可以用ES6語法Symbol來處理或者根據hasOwnProperty判斷,但其實也會變得更冗長
3. ES6提供的class,就可以達到繼承Array成為子類別
```javascript=
class MovieCollection extends Array {
constructor(name, ...items) {
super(...items);
this.name = name;
}
add(movie) {
this.push(movie);
}
topRated(limit = 10){
return this.sort((a, b) => (a.stars > b.stars ? -1 : 1)).slice(0, limit);
}
}
const movies = new MovieCollection('Wes\'s Fav Movies',
{name: 'Bee Movie', stars: 10},
{name: 'Star Wars Trek', stars: 1},
{name: 'Virgin Suicides', stars: 7},
{name: 'King of the Road', stars: 8}
);
```
4. 企業需要可靠的執行環境才能維護,如果團隊中的每個人都會這麼處理,那麼可能碰到命名衝突、不兼容的環境、維運的夢魘
### 支持派的論點
1. 方便,尤其對於僅個人使用的代碼
2. 平常沒有必需使用for in的理由(但three.js似乎用了不少)
參考
https://www.kirupa.com/html5/extending_built_in_objects_javascript.htm
https://stackoverflow.com/questions/948358/adding-custom-functions-into-array-prototype
https://hacks.mozilla.org/2015/08/es6-in-depth-subclassing/
https://github.com/wesbos/es6-articles/blob/master/54%20-%20Extending%20Arrays%20with%20Classes%20for%20Custom%20Collections.md