Object 屬性與方法全接觸

一切對象都是 Object 的實例,一切函數都是 Function 的實例,Object 是構造函數,函數是 Function 的實例,Function.prototype 是對象,對象是 Object 的實例,能夠說 Object 與 Function 是一對密不可分的兄弟,讓咱們一塊兒解開 Object 與 Function 的神祕面紗,本章主要了解 Object 相關知識,下章再來看 Functiongit

Function instanceof Object // true
Object instanceof Function // true

Object 構造函數能夠建立一個對象包裝器api

JS 中全部對象都來自 Object, 全部對象從 Object.prototype 繼承方法和屬性數組

傳入的值爲 null 或 undefined 將返回一個 {} 空對象瀏覽器

Object(null) // {}
Object(undefined) // {}

Object() 等同於 new Object()函數

對象字面量

由 {} 包含零個或多個鍵值對組成以逗號分隔的列表構成性能

對象字面量是屬性名及其關聯值的集合
必須由 逗號 分隔
下面是 ES6(ECMAScript 2015) 中對象的定義方式this

const a = 1;
var obj = {
    a,
    get a(){},
    set a(){},
    ['a' + 'b']: 'hello',
    say(){},
    baz: { b: 2 }
}

重複屬性

重複的屬性,後面的屬性會覆蓋前面的屬性,在ES5中,重複的屬性會拋出語法錯誤 SyntaxErrorprototype

對象合併

Object.assign() 能夠合併兩個對象,也可使用展開符 ... 合併兩個對象,Object.assign() 會觸發 setter,而展開操做符則不會code

var a = { a: 1 };
var b = { b: 2 };

var mergedObj = Object.assign({}, a, b)

var mergedObj = { ...a, ...b }

變動對象原型

若是給對象的 _proto_ 賦值爲 null, 則會更改對象原型,賦值爲其它任何值則不會改變對象原型對象

Object.getPrototypeOf({__proto__:null}) === null
// true

Object.getPrototypeOf({__proto__:{}}) === null
// false

在對象字面值中,只有一次改變原型的機會,屢次變動會報語法錯誤

不使用 : 定義 _proto__ 不會變動原型,而是會變成對象的普通屬性

var __proto__ = "variable";
var obj1 = { __proto__ };
Object.getPrototypeOf(obj1) === Object.prototype
// true

var obj2 = { __proto__() { return "hello"; } };
obj2.__proto__() === "

與JSON區別

對象字面量 與 JSON(JavaScript Object Notation) 的區別

JSON 只容許 以 "property": value 的形式定義屬性,且屬性名必須以 " 號括起來,屬性定義不容許簡寫
JSON 中的屬性值只容許 字符串、數字、數組、true、false、null或其它JSON對象
JSON 中屬性值不容許是函數
JSON.parse() 不會處理計算屬性名,會拋語法錯誤

Object.length

返回 Object() 構造函數形參數量,值爲 1

Object.prototype

Object.prototype.hasOwnProperty()

檢查對象自身中是否有某屬性(忽略原型鏈中的屬性)

Object.prototype.isPrototypeOf()

檢查當前原型是否在指定對象的原型中 (做用等同於 instanceof)

Object.prototype.propertyIsEnumerable()

判斷屬性是否可枚舉

Object.prototype.toLocaleString()

返回對象的字符串表示(用於派生對象重載)

Array.prototype.toLocaleString([locales[,options]])
Number.prototype.toLocaleString([locales[,options]])
Date.prototype.toLocaleString([locales[,options]])

新的 locales 和 options 參數讓應用程序能夠指定要進行格式轉換的語言,而且定製函數的行爲

在舊的實現中,會忽略 locales 和 options 參數,使用的語言環境和返回的字符串的形式徹底取決於實現方式。

locales 和 options 不一樣的瀏覽器及版本有兼容性問題,因此這個api並無獲得普遍的應用

var prices = ['¥7', 500, 8123, 12];
prices.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' });

// "¥7,¥500,¥8,123,¥12"

const num = 2333333;
num.toLocaleString('zh', { style: 'decimal' });   //2,333,333
num.toLocaleString('zh', { style: 'percent' });   //233,333,300%

const num = 2333333;
num.toLocaleString('zh', { style: 'currency', currency: 'CNY' });    //¥2,333,333.00
num.toLocaleString('zh', { style: 'currency', currency: 'cny', currencyDisplay: 'code' });      //CNY2,333,333.00

let num = 2333.3;
num.toLocaleString('zh', { minimumIntegerDigits: 5 });        //02,333.3
//若是不想有分隔符,能夠指定useGrouping爲false
num.toLocaleString('zh', { minimumIntegerDigits: 5, useGrouping: false });        //02333.3
num.toLocaleString('zh', { minimumFractionDigits: 2, useGrouping: false });     //2333.30

num = 666.666
num.toLocaleString('zh', { maximumFractionDigits: 2, useGrouping: false });     //666.67

Object.prototype.toString()

返回對象的字符串表示

使用 toString 來檢查對象類型

function isNull(){
Object.prototype.toString.call(obj) === '[object Null]'
}

Object.prototype.valueOf()

返回一個表示該對象的字符串

Object.assign()

將可枚舉的屬性從一個或多個源拷貝到目標對象

可是隻能深拷貝非嵌套的對象,嵌套屬性爲淺拷貝

簡單的深拷貝

JSON.parse(JSON.stringify(Obj)), 缺點是會破壞對象的原型鏈,而且會丟失對象的方法

Object.create(proto, [propsObj])

使用指定的原型建立對象

// ES5實現 (不支持 propsObj)
function extend(proto){
  function F(){};
  F.prototype = proto;
  return new F();
}

// 建立一個原型爲null的空對象
var o = Object.create(null)

var o = {}
// 至關於
var o = Object.create(Object.prototype)

// 爲所建立的對象添加屬性 (若是缺省配置,默認爲false)
var o = Object.create(Object.prototype, {
  foo: {
    writeable: true,
    configurable: true,
    enumerable: true,
    value: 'hello'
  }
})

function MyClass (){}
var o = new MyClass()
// 至關於
var o = Object.create(Myclass.prototype)

Object.assign 只會拷貝源對象自身且可枚舉的屬性,會調用 源對象的 get 和 目標對象的 set 方法,
若是源對象的屬性 get 方法是自定義的,合併後,將會丟失
合併時,不會跳過那些值爲 null 或 undefined 的源對象
Ojbect.assign 的ES5中的 polyfill

Object.defineProperty(Object, 'assign', {
  value: function assign(target, varArgs) {
    'use strict';
    if (target == null) {
      throw new TypeError('Connot convert undefined or null to object');
    }

    var to = Object(target);

    for (var index = 1; index < arguments.length; index++) {
      var nextSource = arguments[index]
      for (var nextKey in nextSource) {
        if(Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
          to[nextKey] = nextSource[nextKey];
        }
      }
    }

    return to;
  },
  writeable: true,
  configurable: true,
})

Object.defineProperty(obj, prop, descriptor)

定義或修改屬性對象

obj: 要定義屬性的對象
prop: 屬性名稱
descriptor: 屬性描述

屬性描述 descriptor 分爲兩種:數據描述符 和 存取描述符

數據描述符:一個有值的屬性,可配置 是否可枚舉、是否可配置、是否可賦值 及 value值

存取描述符:有 getter、setter 函數的屬性,也可配置 是否可配置及是否可枚舉
屬性描述只能是 數據描述 或 存取描述 中的一種

數據描述符 描述的屬性只可能有 configurable、enumerable、writeable、value

存取描述符 描述的屬性只可能有 get、set、configurable、enumerable 四個配置
若是一個描述符不具備value,writable,get 和 set 任意一個關鍵字,那麼它將被認爲是一個數據描述符

// 數據描述符 描述的屬性
Object.defineProperty({}, 'a', {
  // 是否可枚舉 決定了是否可被 for...in 和 Object.keys() 獲取屬性名
  enumerabel: true,
  // 屬性描述是否可改變,該屬性是否可刪除,當前配置爲false時,不能在數據和訪問器屬性類型之間切換,不可刪除,除 writable 以外的描述不可修改
  configurable: true,
  // 是否可賦值
  writeable: true,
  // 屬性值,默認爲 undefined
  value: 1
})

// 存取描述符 描述的屬性
var bValue;
Object.defineProperty({}, 'b', {
  get: function(){
    return value;
  },
  set: function(newValue){
    bValue = newValue
  },
  enumerable: true,
  configurable: true,
})
function Archiver () {
  var temp = null;
  var history = []

  Object.defineProperty(this, 'temp', {
    get: function () {
      console.log('get')
      return temp;
    },
    set: function (newV) {
      temp = newV
      history.push({val: temp})
    }
  })

  this.getHistory = function(){ return history; };
}

var arc = new Archiver()

arc.temp
arc.temp = 11
arc.temp = 13
arc.getHistory() // [{ val: 11 }, { val: 13 }]

Object.defineProperties(obj, props)

定義或修改多個屬性對象 與 Object.defineProperty 同樣

var obj = {};
Object.defineProperties(obj, {
  'property1': {
    value: true,
    writable: true
  },
  'property2': {
    value: 'Hello',
    writable: false
  }
});

Object.entries()

返回可枚舉屬性的鍵值對數組

// 獲取
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]

// 遍歷 for...of
const obj = { a: 5, b: 7, c: 9};
for(const [key, value] of Object.entries(obj)) {
  console.log(`${key} ${value}`);
}

// 遍歷 forEach
Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
});

// Object 轉 Map
new Map(Object.entries(obj))

Object.freeze()

凍結一個對象,被凍結的對象,不可添加、刪除、修改其屬性,也不可修改屬性的描述配置,返回被凍結的對象

只能凍結對象中的第一層的常量對象,不可凍結複雜對象

obj1 = {
  internal: {}
};

Object.freeze(obj1);
obj1.internal.a = 'aValue';

obj1.internal.a // 'aValue'
自定義一個深凍結函數

function deepFreeze(obj){
  const propNames = Object.getOwnPropertyNames(obj);

  propNames.forEach(name => {
    const prop = obj[name];

    if(typeof prop === 'object' && prop !== null) {
      deepFreeze(prop)
    }
  })

  return Object.freeze(obj)
}

Object.isFrozen()

返回指定對象是不是凍結對象

Object.seal()

封閉一個對象,對象屬性不可刪除,不可增長新屬性,不可修改屬性描述配置,但 能夠修改屬性值

const object1 = {
  property1: 42
};

Object.seal(object1);
object1.property1 = 33;
console.log(object1.property1);
// expected output: 33

delete object1.property1; // cannot delete when sealed
console.log(object1.property1);
// expected output: 33
Object.isSealed()

返回指定對象是不是封閉對象

獲取對象自身可枚舉的屬性

Object.keys()

與 for...in 不一樣的是:for...in 還會遍歷對象原型鏈中的屬性

使用 for...in 獲取對象自身可枚舉的屬性

for(key in obj) {
obj.hasOwnProperty(key){
console.log(key)
}
}

Object.values()

返回可枚舉的屬性數組

const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]

Object.getOwnPropertyNames()

獲取對象自身的屬性 (枚舉&不能枚舉)

獲取對象自身不可枚舉的屬性?

var allProps = Object.getOwnPropertyNames(obj)
var enumProps = Object.keys(obj)
var noenumProps = allProps.filter(v => enumProps.indexOf(v) === -1)

Object.getOwnPropertySymbols()

返回對象自身全部 Symbol 屬性數組

對象自身屬性 包含了兩種類型,一種是 字符串屬性,一種是 Symbol 數據屬性,
字符串屬性名可由 Object.getOwnPropertyNames() 來獲取
Symbol 屬性名可由 Ojbect.getOwnPropertySymbols() 來獲取
默認對象是不含有 Symbol 屬性的,除非手動添加了 Symbol 屬性

Object.getOwnPropertyDescriptor()

返回 對象自身屬性的 描述配置信息

Object.getOwnPropertyDescriptors()

返回 對象自身全部屬性的 描述配置信息

屬性描述分爲兩種:存取描述 與 數據描述

var o = { get foo() { return 17; } };
var d = Object.getOwnPropertyDescriptor(o, "foo");
// d {
//   configurable: true,
//   enumerable: true,
//   get: /*the getter function*/,
//   set: undefined
// }

var o = { bar: 42 };
var d = Object.getOwnPropertyDescriptor(o, "bar");
// d {
//   configurable: true,
//   enumerable: true,
//   value: 42,
//   writable: true
// }

Object.assign() 沒法拷貝源對象屬性的特性,且屬性描述會被轉爲數據描述,也沒法拷貝源對象的原型

使用 Object.create() 能夠完整的淺拷貝一個對象

Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj))

Object.getPrototypeOf()
返回指定對象的原型

var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true

Object.setPrototypeOf()

設置指定對象的原型

這個方法是ES6中的方法,用於替換ES5中 Object.prototype.__proto__ = newProto 的方式修改原型

修改原型對於瀏覽器是一個耗性能的方法,應避免去修改原型,使用 Object.create() 去建立新的對象

Object.is()

同值相等比較 比較兩個值是否相等

與抽象相等 == 區別:
同值相等不會去隱式轉換數據類型

與嚴格相等 === 區別:
同值相告對於 -0與+0 返回 false, 而嚴格相等返回 true
對於 NaN 與 NaN,同值相等返回 true, 嚴格相等返回 false

Object.is(0, -0);            // false
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true

0 === -0 //true
+0 === -0 //true
NaN === NaN //false

Object.isExtensible()

判斷指定對象是否能夠擴展 (是否能夠添加屬性及原型)返回 Boolean

var empty = {};
Object.isExtensible(empty); // === true

Object.preventExtensions()

禁止對象擴展 已有的屬性能夠修改、刪除,但不能再添加新的屬性

相關文章
相關標籤/搜索