2017年9月8日 星期五

array 的 pop、shift、splice 用法

都是刪除

※使用方法

let arr = new Array("a", "b", "c", "d", "e");
console.info(arr); // a b c d e
    
// pop 刪除最後一個元素,返回值為被刪除的元素
// let pop = arr.pop();
// console.info(arr); // a b c d
// console.info(pop); // e
    
// shift 刪除第一個元素,返回值為被刪除的元素
// let shift = arr.shift();
// console.info(arr); // b c d e
// console.info(shift); // a
    
// splice 最靈活的刪除,也可適情況新增
// 第一個參數,表示從指定的索引開始刪到最後,必要
// 第二個參數,表示從第一個參數之後的索引開始刪除幾個元素,非必要
// 第三個參數是「...」,刪除的索引可從第三個參數之後加入這裡輸入的元素,非必要
let splice = arr.splice(2, 3, "f", "g");
console.info(arr); // a b f g
console.info(splice); // c d e




※splice 刪除常見錯誤

let arr = new Array("a", "b", "c", "d", "e");
console.info(arr); // a b c d e
    
// for(let i=0; i<arr.length; i++) {
//     if(arr[i] == "a" || arr[i] == "b") {
//         arr.splice(i, 1);
//         // i--;
//     }
// }
    
arr.forEach((value, i) => {
    if(value == "a" || value == "b") {
        arr.splice(i, 1);
        // i--; 無效
    }
});
    
// 以下是用 jQuery 的 each,也是一樣的情形
// $(arr).each((i, value) => {
//     if(value == "a" || value == "b") {
//         arr.splice(i, 1);
//         i--; 無效
//     }
// });
    
// $.each(arr, (i, value) => {
//     if(value == "a" || value == "b") {
//         arr.splice(i, 1);
//         i--; 無效
//     }
// });
console.info(arr); // b c d e,非預期的 c d e

※以上都是 index 刪除後會自動往上一格,所以可用 i-- 來解決,但 forEach 是無效的

2017年9月5日 星期二

Prototype chain

※Prototype chain (原形鏈)

function Xxx(){}
    
let x1 = new Xxx();
Xxx.prototype.abc = 1;
    
let x2 = new Xxx();
x2.def = 2;
    
let x3 = new Xxx();
x3.ghi = 3;
    
console.log(x1.abc); // 1
console.log(x2.abc); // 1
console.log(x3.abc); // 1
    
console.log(x1.def); // undefined
console.log(x2.def); // 2
console.log(x3.def); // undefined
    
console.log(x1.ghi); // undefined
console.log(x2.ghi); // undefined
console.log(x3.ghi); // 3

※原形就是物件的公用空間,誰 new 這個物件,誰就可以使用,如下圖:
※要注意的是,原形也是物件,所以物件都有公用空間,也就是原形的原形,但只有定義兩層而已

※可以用__proto__屬性查看
function Xxx(){}
let x = new Xxx();
Xxx.prototype.abc = 2;
    
console.log(x.__proto__);
console.log(x.__proto__.__proto__);
console.log(x.__proto__.__proto__.__proto__); // null

※Chrome 的圖

※兩個紅框的內容是一樣的


※原形的原形的方法

function Xxx(){}
let x = new Xxx();
x.ooo = 1;
Xxx.prototype.abc = 2;
    
console.log("ooo" in x); // true
console.log(x.hasOwnProperty("ooo")); // true
    
console.log("abc" in x); // true
console.log(x.hasOwnProperty("abc")); // false,只找自己,不會往prototype找
    
// 還可以使用 hasOwnProperty 找 hasOwnProperty
console.log(x.hasOwnProperty("hasOwnProperty")); // false
console.log(x.__proto__.hasOwnProperty("hasOwnProperty")); // false
console.log(x.__proto__.__proto__.hasOwnProperty("hasOwnProperty")); // true

※如果定義和原形一樣的變數,會由自己先找,沒有才往原形找,再沒有又往原形的原形找,再沒有,就回傳 undefined

※直接印 x ,會去找原形的原形的 toString方法,想改可以用 x.toString = () => {return "";}; 去覆寫
但較新的瀏覽器版本已經不呼叫 toString 方法了