Javascript基礎鞏固系列——標準庫Object對象

全手打原創,轉載請標明出處:https://www.cnblogs.com/dreamsqin/p/13714848.html, 多謝,=。=~(如果對你有幫助的話請幫我點個贊啦)

重新學習JavaScript是因爲當年轉前端有點兒趕鴨子上架的意味,我一直在反思我的知識點總是很零散,不能在腦海中形成一個完整的體系,所以這次想通過再次學習將知識點都串聯起來,結合日常開發的項目,達到溫故而知新的效果。與此同時,總結一下我認爲很重要但又被我遺漏的知識點~

Object()方法

可以當作工具方法使用,將任意值轉爲對象,如果參數爲空(或者爲undefinednull),返回一個空對象;如果參數是原始類型的值,會轉爲對應的包裝對象;如果參數是一個對象,則直接返回該對象(特殊用法,用於判斷變量是否爲對象)。

var obj = Object(1);
obj instanceof Object // true
obj instanceof Number // true

// 判斷變量是否爲對象
function isObject(value) {
  return value === Object(value);
}

isObject([]) // true
isObject(true) // false

Object的靜態方法

指部署在Object對象自身的方法。

  • Object.keys()Object.getOwnPropertyNames()
    參數爲一個對象,返回一個數組,數組爲該對象自身的(而不是繼承的)所有屬性名,區別是前者只返回可枚舉(enumerable: true)的屬性,由於 JavaScript 沒有提供計算對象屬性個數的方法,所以可以用這兩個方法代替。
var a = ['Hello', 'World'];
Object.keys(a) // ["0", "1"]
Object.getOwnPropertyNames(a) // ["0", "1", "length"]

var obj = {
  p1: 123,
  p2: 456
};
Object.keys(obj).length // 2
Object.getOwnPropertyNames(obj).length // 2
  • Object.getOwnPropertyDescriptor()
    獲取某個屬性的描述對象(屬性描述對象說明見下文),第一個參數是目標對象,第二個參數是一個字符串,對應目標對象的某個屬性名,只能用於對象自身的屬性,不能用於繼承的屬性。
var obj = { p: 'a' };

Object.getOwnPropertyDescriptor(obj, 'p')
// Object { value: "a",
//   writable: true,
//   enumerable: true,
//   configurable: true
// }
  • Object.defineProperty()
    通過描述對象(屬性描述對象說明見下文),定義或修改某個屬性,然後返回修改後的對象,參數:屬性所在對象、屬性名字符串、屬性描述對象。
var obj = Object.defineProperty({}, 'p', {
  value: 123,
  writable: false,  // 如果原型對象的某個屬性的writable爲false,那麼子對象將無法自定義這個屬性,但可以通過defineProperty修改value來繞過限制。
  enumerable: true,
  configurable: false
});

obj.p // 123

obj.p = 246;  // 正常模式下只是默默失敗,嚴格模式(use strict)下會報錯
obj.p // 123
  • Object.defineProperties()
    通過描述對象(屬性描述對象說明見下文),定義或修改多個屬性,然後返回修改後的對象,參數:屬性所在對象、屬性名與屬性描述對象的鍵值對對象。
var obj = Object.defineProperties({}, {
  p1: { value: 123, enumerable: true },
  p2: { value: 'abc', enumerable: true },
  p3: { get: function () { return this.p1 + this.p2 },
    enumerable:true,
    configurable:true
  }
});

obj.p1 // 123
obj.p2 // "abc"
obj.p3 // "123abc"
  • Object.create()
    可以指定原型對象和屬性,返回一個新的對象。
  • Object.getPrototypeOf()
    獲取對象的Prototype對象。

Object的實例方法

指定義在Object.prototype對象上的方法,所有Object的實例對象都繼承了這些方法。

  • Object.prototype.valueOf()
    返回當前對象對應的值,默認情況下返回對象本身,主要用途是JavaScript自動類型轉換時會默認調用這個方法。
var obj = new Object();
1 + obj // "1[object Object]"
  • Object.prototype.toString()
    返回當前對象對應的字符串形式,默認情況下返回類型字符串"[object object]"(第二個值表示該對象的構造函數),數組、字符串、函數、Date 對象都分別部署了自定義的toString方法,覆蓋了原生的Object.prototype.toString方法。
var o = {a:1};
o.toString() // "[object Object]"

// 數組
[1, 2, 3].toString() // "1,2,3"

// 字符串
'123'.toString() // "123"

// 函數
(function () {
  return 123;
}).toString()
// "function () {
//   return 123;
// }"

// Date對象
(new Date()).toString()
// "Tue May 10 2016 09:11:31 GMT+0800 (CST)"

特殊應用:用於判斷數據類型,由於實例對象可能會自定義toString方法,覆蓋掉Object.prototype.toString方法,所以可以利用call直接調用原型方法。

Object.prototype.toString.call(value)

//數值:返回[object Number]
//字符串:返回[object String]
//布爾值:返回[object Boolean]
//undefined:返回[object Undefined]
//null:返回[object Null]
//數組:返回[object Array]
//arguments 對象:返回[object Arguments]
//函數:返回[object Function]
Object.prototype.toString.call(Math) // "[object Math]"
//Error 對象:返回[object Error]
//Date 對象:返回[object Date]
//RegExp 對象:返回[object RegExp]
//其他對象:返回[object Object]

//一個比typeof運算符更準確的類型判斷函數
var type = function (o){
  var s = Object.prototype.toString.call(o);
  return s.match(/\[object (.*?)\]/)[1].toLowerCase();
};

type({}); // "object"
type([]); // "array"
type(5); // "number"
type(null); // "null"
type(); // "undefined"
type(/abcd/); // "regex"
type(new Date()); // "date"
  • Object.prototype.toLocaleString()
    返回當前對象對應的本地字符串形式,主要作用是留出一個接口,讓各種不同的對象實現自己版本的toLocaleString,用來返回針對某些地域的特定的值,目前ArrayNumberDate自定義了toLocaleString方法。
var person = {
  toString: function () {
    return 'Henry Norman Bethune';
  },
  toLocaleString: function () {
    return '白求恩';
  }
};
person.toString() // Henry Norman Bethune
person.toLocaleString() // 白求恩

var date = new Date();
date.toString() // "Tue Jan 01 2018 12:01:33 GMT+0800 (CST)"
date.toLocaleString() // "1/01/2018, 12:01:33 PM"
  • Object.prototype.hasOwnProperty()
    判斷某個屬性是否爲當前對象自身的屬性,還是繼承自原型對象的屬性。
var obj = {
  p: 123
};

obj.hasOwnProperty('p') // true
obj.hasOwnProperty('toString') // false
  • Object.prototype.isPrototypeOf()
    判斷當前對象是否爲另一個對象的原型。
  • Object.prototype.propertyIsEnumerable()
    判斷某個屬性是否可枚舉,只能用於判斷對象自身的屬性,對於繼承的屬性一律返回false。
var obj = {};
obj.p = 123;

obj.propertyIsEnumerable('p') // true
obj.propertyIsEnumerable('toString') // false

屬性描述對象

JavaScript 提供了一個內部數據結構,用來描述對象的屬性,控制它的行爲,比如該屬性是否可寫、可遍歷等等。這個內部數據結構稱爲“屬性描述對象”(attributes object)。每個屬性都有自己對應的屬性描述對象,保存該屬性的一些元信息。
PS:value+writable:true屬性與get+set不能共存,在Object.defineProperty()Object.defineProperties()參數裏面的屬性描述對象,writableconfigurableenumerable這三個屬性的默認值都爲false

 // 屬性描述對象的各個屬性稱爲“元屬性”,因爲它們可以看作是控制屬性的屬性
{
  value: 123,  // 屬性值,默認爲undefined
  writable: false,  // 布爾值,表示屬性值(value)是否可改變(即是否可寫),默認爲true
  enumerable: true,  // 布爾值,表示該屬性是否可遍歷,默認爲true(不可遍歷時for...in循環、Object.keys()、JSON.stringify會跳過該屬性)
  configurable: false,  // 布爾值,表示可配置性,默認爲true,控制了屬性描述對象的可寫性(不可配置時無法刪除該屬性,也不得改變該屬性的屬性描述對象(value屬性在writable爲true時除外,writable的true改false除外))
  get: undefined,  // 表示該屬性的取值函數(getter),默認爲undefined,取值時會調用
  set: undefined  // 表示該屬性的存值函數(setter),默認爲undefined,存值時會調用
}
  • 存取器settergetter
    存值函數稱爲setter,使用屬性描述對象的set屬性;取值函數稱爲getter,使用屬性描述對象的get屬性。
// 寫法一(enumerable、configurable默認爲false)
var obj = Object.defineProperty({}, 'p', {
  get: function () {
    return 'getter';
  },
  set: function (value) {
    console.log('setter: ' + value);
  }
});

obj.p // "getter"
obj.p = 123 // "setter: 123"

// 寫法二(更推薦,因爲enumerable、configurable默認爲true)
var obj = {
  get p() {
    return 'getter';
  },
  set p(value) {
    console.log('setter: ' + value);
  }
};

對象的拷貝

將一個對象的所有屬性,拷貝到另一個對象,爲了能把存取器定義的屬性也成功拷貝,可以使用以下方法。

var extend = function (to, from) {
  for (var property in from) {
    if (!from.hasOwnProperty(property)) continue;  // 過濾掉繼承的屬性
    Object.defineProperty(
      to,
      property,
      Object.getOwnPropertyDescriptor(from, property)
    );
  }
  return to;
}

extend({}, { get a(){ return 1 } })
// { get a(){ return 1 } })

控制對象狀態

有時需要凍結對象的讀寫狀態,防止對象被改變(但有漏洞:可以通過改變原型對象,來爲對象增加屬性;如果屬性值是對象,就只能凍結屬性指向的對象(即無法指向其他值),而不能凍結對象本身的內容)。JavaScript 提供了三種凍結方法,最弱的一種是Object.preventExtensions,其次是Object.seal,最強的是Object.freeze

  • Object.preventExtensions()
    可以使得一個對象無法再添加新的屬性。
var obj = new Object();
Object.preventExtensions(obj);

Object.defineProperty(obj, 'p', {
  value: 'hello'
});
// TypeError: Cannot define property:p, object is not extensible.

obj.p = 1;
obj.p // undefined
  • Object.isExtensible()
    用於檢查一個對象是否使用了Object.preventExtensions方法,也就是說,檢查是否可以爲一個對象添加屬性。
var obj = new Object();

Object.isExtensible(obj) // true
Object.preventExtensions(obj);
Object.isExtensible(obj) // false
  • Object.seal()
    使得一個對象既無法添加新屬性,也無法刪除舊屬性,實質是把屬性描述對象的configurable屬性設爲false
var obj = { p: 'hello' };
Object.seal(obj);

delete obj.p;
obj.p // "hello"

obj.x = 'world';
obj.x // undefined
  • Object.isSealed()
    用於檢查一個對象是否使用了Object.seal方法。
var obj = { p: 'a' };

Object.seal(obj);
Object.isSealed(obj) // true
Object.isExtensible(obj) // false
  • Object.freeze()
    可以使得一個對象無法添加新屬性、無法刪除舊屬性、也無法改變屬性的值,使得這個對象實際上變成了常量。
var obj = {
  p: 'hello'
};

Object.freeze(obj);

obj.p = 'world';
obj.p // "hello"

obj.t = 'hello';
obj.t // undefined

delete obj.p // false
obj.p // "hello"
  • Object.isFrozen()
    用於檢查一個對象是否使用了Object.freeze方法。
var obj = {
  p: 'hello'
};

Object.freeze(obj);
Object.isFrozen(obj) // true
Object.isExtensible(obj) // false

參考資料

JavaScript 語言入門教程 :https://wangdoc.com/javascript/index.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章