物件

  • 有時物件被稱為關聯式陣列,因其key值可為文字,但本質並非關聯式陣列。

  • 物件內的值所代表的意義,可由命名的key得知。一般javascript套件的設定也是用key-value的方式修改。

  • JavaScript是物件導向的程式語言,但它是使用原型基礎(prototype-based)的設計,而其他的物件導向,大部份都是使用類別基礎(class-based)的設計。

建立新物件

// 法一:從建立空物件開始
var obj={}

// 法二:從建立空物件開始
var person1 = new Object();

person1.name = 'Chris';
person1['age'] = 38;
person1.greeting = function() {
  alert('Hi! I\'m ' + this.name + '.');
}

// 法三:直接代入初始物件
var person1 = new Object({
  name : 'Chris',
  age : 38,
  greeting : function() {
    alert('Hi! I\'m ' + this.name + '.');
  }
});

// 法四:根據現有物件,建立新的物件。
var person2 = Object.create(person1);

物件成員

  • 物件類型使用以屬性與方法為主要組成部份,這兩種合稱為物件成員(member):

    -屬性: 物件可被描述的量化資料。例如水果這個物件,有顏色、產地、大小、重量、甜度等等屬性。 -方法: 物件的動作或行為。例如車子這個物件,它的行為有加速、煞車、轉彎、打方向燈等等的行為或可作的動作。

私有成員

JavaScript截至ES6標準為止,在類別中並沒有像其他程式語言中的私有的(private)、保護的(protected)、公開的(public)這種成員存取控制的修飾關鍵字詞

目前比較簡單常見的區分方式,就是在私有成員(或方法)的名稱前面,加上下底線符號(_)前綴字

在類別定義中可以使用get與set關鍵字,作為類別方法的修飾字,私有屬性或特殊值,才需要用這兩種方法來作取得或設定

class Option {
    constructor(key, value, autoLoad = false) {
        if (typeof key != 'undefined') {
            this['_' + key] = value;
        }
        this.autoLoad = autoLoad;
    }

    get color() {
      if (this._color !== undefined) {
        return this._color
      } else {
        return 'no color prop'
      }
    }

    set color(value) {
      this._color = value
    }
}

const op1 = new Option('color', 'red')
op1.color = 'yellow'

const op2 = new Option('action', 'run')
op2.color = 'yellow' //no color prop

JavaScript中只有靜態方法,沒有靜態屬性

class Student {
    constructor(id, firstName, lastName) {
        this.id = id
        this.firstName = firstName
        this.lastName = lastName

        //這裡呼叫靜態方法,每次建構出一個學生實體就執行一次
        Student._countStudent()
    }

    //靜態方法的定義
    static _countStudent(){
      if(this._numOfStudents === undefined) {
          this._numOfStudents = 1
      } else {
          this._numOfStudents++
      }
    }

    //用getter與靜態方法取出目前的學生數量
    static get numOfStudents(){
      return this._numOfStudents
    }

}

const aStudent = new Student(11, 'Eddy', 'Chang')
console.log(Student.numOfStudents)

const bStudent = new Student(22, 'Ed', 'Lu')
console.log(Student.numOfStudents)

const cStudent = new Student(33, 'Horward', 'Liu')
console.log(Student.numOfStudents)

靜態屬性目前來說有兩種解決方案,一種是使用ES7的Class Properties標準,可以使用static關鍵字來定義靜態屬性,另一種是定義到類別原本的定義外面

// ES7語法方式
class Video extends React.Component {
  static defaultProps = {
    autoPlay: false,
    maxLoops: 10,
  }
  render() { ... }
}
// ES6語法方式
class Video extends React.Component {
  constructor(props) { ... }
  render() { ... }
}

Video.defaultProps = { ... }

繼承

用extends關鍵字可以作類別的繼承,而在建構式中會多呼叫一個super()方法,用於執行上層父母類別的建構式之用

class Point {
    constructor(x, y) {
        this.x = x
        this.y = y
    }
    toString() {
        return '(' + this.x + ', ' + this.y + ')';
    }
}

class ColorPoint extends Point {
    constructor(x, y, color) {
        super(x, y)
        this.color = color
    }
    toString() {
        return super.toString() + ' in ' + this.color
    }
}

物件的拷貝

Object.assign() 合併二個物件,若其中一個為空,就是拷貝。

//物件拷貝
const aObj = { a: 1, b: 'Test' }
const copy = Object.assign({}, aObj)
console.log(copy) // {a: 1, b: "Test"}

//物件合併
const bObj = { a: 2, c: 'boo' }
const newObj = Object.assign(aObj, bObj)
console.log(newObj) //{a: 2, b: "Test", c: "boo"}

JSON.stringify(物件)=>字串 JSON.parse(字串)=>物件

undefined判斷方式

//判斷鍵是否存在
typeof obj.key !== 'undefined'

//判斷值是否存在
obj.key !== undefined
obj['key'] !== undefined

jQuery的物件合併是用$.extend

let data1 ={}
let data2 = {}
let data3 = {}
$.extend(data1,data2,data3)

Error物件

Error物件只能使用new運算符來建立

try {
  //自訂丟出例外
  throw new Error('Whoops!');

} catch (e) {
  console.log(e.name + ': ' + e.message);

}

Date物件

Date物件只能使用new運算符來建立

取得日期

const dateObject = new Date() //Fri Jul 15 2016 16:23:49 GMT+0800 (CST)
const date = dateObject.getDate() //15
const day = dateObject.getDay()  //5
const month = dateObject.getMonth()  //6
const year = dateObject.getFullYear()  //2016

const hour = dateObject.getHours() //0-24
const minute = dateObject.getMinutes() //0-59
const second = dateObject.getSeconds() //0-59
const ms = dateObject.getMilliseconds() //0-999
// getDate: 取得日期的值,範圍為1-31
// getDay: 取得星期幾的值,範例為0-6
// getMonth: 取得月份的值,範例為0-11

設定日期

const dateObject = new Date()

dateObject.setFullYear(2015) //年,4位數字
dateObject.setMonth(0) //月,陣列索引值 0-11
dateObject.setDate(24) //日,正負整數

本地化與格式化

const date = new Date()

console.log(date.toLocaleString())     //2016/9/14 下午4:33:41
console.log(date.toLocaleDateString())  //2016/9/14
console.log(date.toLocaleTimeString()) //下午4:33:41

日期比較

Date物件可以直接比較大小

const myDate = new Date()
const today = new Date()

myDate.setFullYear(2015,8,9)

if ( myDate > today ){
  console.log('今天比2015.8.9日早')
} else {
  console.log('今天比2015.8.9日晚')
}

//用getTime()取得毫秒相減計算相差時間
//除1000*60*60*24為了取得天數
let diff= (today.getTime()-myDate.getTime())/(1000*60*60*24)
//於一段時間後處理
setTimeout(處理函數,時間)

//於間隔時間處理
setInterval(處理函數,時間)

物件操作

//方法1:利用 . 操作屬性
//只能在 key 不包含符號的狀況下使用

var myObj = { prop1: 'hello world', "prop-2": 123 };
// read property
console.log(myObj.prop1);            
// "hello world"
console.log(myObj.prop-2);            
// NaN


//方法2:利用 [] 操作屬性
var myObj = { prop1: 'hello world', "prop-2": 123, "777": 456 };

myProperty = 777;
console.log(myObj[prop1]);                
// "hello world"
console.log(myObj["prop-2"]);            
// 123
console.log(myObj[myProperty]);            
// 456


//新增/更新 屬性
var myObj = { prop1: 'hello world' };
myProperty = 777;
//更新
myObj[prop1] = 'hey world';
//新增
myObj["prop-2"] = 123;
//新增
myObj[myProperty] = 456;

console.log(myObj[prop1]);                
// "hey world"
console.log(myObj["prop-2"]);            
// 123
console.log(myObj[myProperty]);            
// 456

//刪除
delete myObj.prop1;
delete myObj[myProperty];

物件轉化為陣列

//1.物件中有物件
list = {
  "1234567890": {
    id: "1234567890",
    name: "Nina Ricci",
  },
  "2345678901": {
    id: "2345678901",
    name: "Hello Kitty",
  },
  "3456789012": {
    id: "3456789012",
    name: "Pusheen the cat",
  },
}

//取得 key 的陣列
const idList = Object.keys(list);
idList // ["1234567890", "2345678901", "3456789012"]

//取得 value中name的陣列
const nameList = Object.values(list).
map(item => item.name);
//nameList 
// ["Nina Ricci", "Hello Kitty", "Pusheen the cat"]

// 另有 Object.entries() 可將物件轉為陣列


//2.陣列中有物件1
const list = [
  {
    id: "1234567890",
    name: "Nina Ricci",
  },
  {
    id: "2345678901",
    name: "Hello Kitty",
  },
  {
    id: "3456789012",
    name: "Pusheen the cat",
  },
];

const idList = list.map(item => Object.values(item)[0]); 
// item是物件,轉為陣列後,0 表示第一個屬性值
idList // ["1234567890", "2345678901", "3456789012"]


// 2.陣列中有物件2

list = [
  {
    "1234567890": "Nina Ricci",
  },
  {
    "2345678901": "Hello Kitty",
  },
  {
    "3456789012": "Pusheen the cat",
  },
]


const idList = list.map(item => Object.keys(item)[0]);
idList // ["1234567890", "2345678901", "3456789012"]


const nameList = list.map(item => Object.values(item)[0]);
nameList // ["Nina Ricci", "Hello Kitty", "Pusheen the cat"]

Last updated