Object()的方法一覽

在JavaScript中,萬物皆來自對(duì)象,但是對(duì)Object()這個(gè)對(duì)象的構(gòu)造函數(shù)卻一知半解掷贾,所以借這個(gè)機(jī)會(huì)來縷清楚Object的方法倦春,并提供低版本的瀏覽器中兼容方法户敬。

//從chrome瀏覽器中的控制臺(tái)輸入Object.getOwnPropertyNames(Object),就能夠得到Object對(duì)象所有自身屬性和方法。
Array ["length", "name", "arguments", "caller", "prototype", "assign", "getOwnPropertyDescriptor",
"getOwnPropertyDescriptors", "getOwnPropertyNames", "getOwnPropertySymbols", "is", "preventExtensions", "seal",
"create", "defineProperties", "defineProperty", "freeze", "getPrototypeOf", "setPrototypeOf", "isExtensible",
"isFrozen", "isSealed", "keys", "entries", "values"]
//從輸出臺(tái)中我們可以知道Object共有25個(gè)屬性和方法溅漾,當(dāng)然由于瀏覽器的兼容性問題山叮,在Firefox瀏覽器中輸入,得到如下
Array [ "assign", "getPrototypeOf", "setPrototypeOf", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors",
"keys", "values", "entries", "is", "defineProperty","defineProperties","creat","getOwnPropertyNames",
"getOwnPropertySymbols","preventExtensions", "seal","isFrozen", "isSealed","prototype","length","name",
"freeze","isExtensible"]
//所以為了最大限度的得到Object中的方法添履,我將以chrome版本得到的數(shù)據(jù)為基準(zhǔn)屁倔,對(duì)Object的方法進(jìn)行解析,一些還處于試驗(yàn)
//狀態(tài)也會(huì)提到暮胧。

Object.assign()

Object.assign(target,source) 中將sources對(duì)象中所有可枚舉的屬性的值復(fù)制到目標(biāo)的對(duì)象中锐借,其會(huì)返回目標(biāo)對(duì)象。該方法的兼容性不是很好往衷,IE全面淪陷钞翔,在移動(dòng)端方面,僅有少數(shù)的瀏覽器才兼容該方法席舍。幸好的是在MDN上提供了兼容的方法布轿。

if(typeof Object.assign!='function'){
  Object.assign = function(target){
    'use strict';
    if(target = null){
      throw new TypeError('Cannot convert undefined or null to object');
    }
    target = Object(target);
    for(var index=0;index<arguments.length;index++){
      var source = arguments[index];
      if(source!=null){
        for(var key in source){
          if(Object.prototype.hasOwnProperty.call(source,key)){
            target[key] = source[key];
          }
        }
      }
    }
    return target;
  }
}

其實(shí)如果我們仔細(xì)觀看源碼的時(shí)候就會(huì)發(fā)現(xiàn)一個(gè)事實(shí),那就是Object.assign()只是對(duì)一級(jí)屬性進(jìn)行復(fù)制,而不會(huì)對(duì)對(duì)象里面的對(duì)象進(jìn)行深度拷貝汰扭,如果出現(xiàn)同名屬性的key值稠肘,那么后者會(huì)覆蓋前者,并不能做到完整的融合萝毛,如果要進(jìn)行融合的話项阴,可以前往depp-assign中閱讀

Object.create()

Object.create(__proto__,[properties]) 該方法將__proto__作為原型對(duì)象笆包,并將[properties]作為新對(duì)象的屬性环揽。

Object.defineProperty()

Object.defineProperty(obj,prop,descriptor) 方法在obj對(duì)象上對(duì)prop屬性進(jìn)行定義或修改,其中descriptor為被定義或修改的屬性符庵佣。其中對(duì)于descriptor屬性符可以設(shè)置的值如下顯示:

  • 【value】表示屬性的值歉胶,默認(rèn)為undefined
  • 【writable】該屬性是否為可寫,如果直接在對(duì)象上定義屬性巴粪,則默認(rèn)為true跨扮。如果設(shè)置為false,則屬性僅為可讀验毡。
  • 【configurable】 如果為false的話衡创,則不能修改(writabel,configurable,enumerable),如果直接在對(duì)象上定義屬性晶通,則默認(rèn)為true
  • 【enumerable】是否能夠被枚舉璃氢,如果直接在對(duì)象上定義屬性,則默認(rèn)為true狮辽。
  • 【get】當(dāng)對(duì)象訪問prop屬性的實(shí)話一也,會(huì)調(diào)用這個(gè)方法,并返回結(jié)果喉脖。默認(rèn)為undefined
  • 【set】當(dāng)對(duì)象設(shè)置該屬性的時(shí)候椰苟,會(huì)調(diào)用這個(gè)方法,默認(rèn)為undefined树叽。

在MVVM框架中的雙向數(shù)據(jù)綁定是通過 Object.defineProperty() 來實(shí)現(xiàn)的舆蝴,其核心的代碼如下所示:

function defineReactive(obj, key, value) {
    var dep = new Dep()
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter() {
            if (Dep.target) {
                dep.depend()
            }
            return value
        },
        set: function reactiveSetter(newVal) {
            if (value === newVal) {
                return
            } else {
                value = newVal
                dep.notify()
            }
        }
    })
}

Object.defineProperty(obj,prop,descriptor) 目前兼容性做的不錯(cuò),移動(dòng)端上兼容絕大部分的瀏覽器题诵,PC上也能夠兼容到IE9及以上洁仗。注意,該方法在IE8上也是能夠使用的性锭,但是其只能夠傳入DOM對(duì)象赠潦,如果傳入其他對(duì)象會(huì)報(bào)錯(cuò)〔莞裕可能有人會(huì)對(duì)該方法的作用產(chǎn)生疑問她奥,其實(shí)該方法極大的優(yōu)化了對(duì)象的獲取和修改屬性方式瓮增,以下是來自騰訊AlloyTeam的一個(gè)示例:

//當(dāng)做動(dòng)畫效果的時(shí)候,常常這樣做哩俭,非常的繁瑣
var targetDom = document.getElementById('target');
var transformText = 'translateX(' + 10 + 'px)';
targetDom.style.webkitTransform = transformText;
targetDom.style.transform = transformText;
//有了Object.defineProperty()之后就可以這樣做了
Object.defineProperty(targetDom, 'translateX', {
    set: function(value) {
         var transformText = 'translateX(' + value + 'px)';
        dom.style.webkitTransform = transformText;
        dom.style.transform = transformText;
    }
}
//這樣再后面調(diào)用的時(shí)候, 十分簡(jiǎn)單
dom.translateX = 10;
dom.translateX = -10;

可能有人覺得這樣做還是有點(diǎn)繁瑣钉赁,但是我們可以封裝一個(gè)函數(shù)庫專門做動(dòng)畫效果。
具體的GitHub地址可以前往這里觀看Object.defineProperty動(dòng)畫應(yīng)用携茂。

Object.defineProperties()

Object.defineProperties(obj,props) 方法直接在一個(gè)對(duì)象上修改或創(chuàng)建屬性,并返回修改后的對(duì)象诅岩,其與上面那個(gè)方法的區(qū)別在于前者可以修改或定義多個(gè)屬性讳苦,但是后者可以定義或修改多個(gè),同時(shí)二者的兼容性一樣吩谦。對(duì)于前者而言鸳谜,有相應(yīng)的polyfill函數(shù)。如下顯示:

function defineProperties(obj, properties)
{
  function convertToDescriptor(desc){
    function hasProperty(obj, prop){
      return Object.prototype.hasOwnProperty.call(obj, prop);
    }

    function isCallable(v){
      // 如果除函數(shù)以外,還有其他類型的值也可以被調(diào)用,則可以修改下面的語句
      return typeof v === "function";
    }

    if (typeof desc !== "object" || desc === null)
      throw new TypeError("不是正規(guī)的對(duì)象");

    var d = {};
    if (hasProperty(desc, "enumerable"))
      d.enumerable = !!desc.enumerable;
    if (hasProperty(desc, "configurable"))
      d.configurable = !!desc.configurable;
    if (hasProperty(desc, "value"))
      d.value = desc.value;
    if (hasProperty(desc, "writable"))
      d.writable = !!desc.writable;
    if (hasProperty(desc, "get")){
      var g = desc.get;
      if (!isCallable(g) && g !== "undefined")
        throw new TypeError("bad get");
      d.get = g;
    }
    if (hasProperty(desc, "set")){
      var s = desc.set;
      if (!isCallable(s) && s !== "undefined")
        throw new TypeError("bad set");
      d.set = s;
    }

    if (("get" in d || "set" in d) && ("value" in d || "writable" in d))
      throw new TypeError("identity-confused descriptor");

    return d;
  }

  if (typeof obj !== "object" || obj === null)
    throw new TypeError("不是正規(guī)的對(duì)象");

  properties = Object(properties);
  var keys = Object.keys(properties);
  var descs = [];
  for (var i = 0; i < keys.length; i++)
    descs.push([keys[i], convertToDescriptor(properties[keys[i]])]);
  for (var i = 0; i < descs.length; i++)
    Object.defineProperty(obj, descs[i][0], descs[i][1]);

  return obj;
}

Object.getOwnPropertyDescriptor(obj,prop)

該方法是用于如果prop屬性存在對(duì)象obj上式廷,則返回其屬性描述符咐扭,如果不存在就返回undefined。該屬性描述符由下面的屬性所組成莱没。

  • 【value】表示屬性的值刽射,僅針對(duì)數(shù)據(jù)屬性描述符有效
  • 【writable】當(dāng)且僅當(dāng)屬性的值可以被改變時(shí)為true词顾。(僅針對(duì)數(shù)據(jù)屬性描述有效)
  • 【configurable】 當(dāng)且僅當(dāng)指定對(duì)象的屬性描述可以被改變或者屬性可被刪除時(shí),為true薛闪。
  • 【enumerable】當(dāng)且僅當(dāng)指定對(duì)象的屬性可以被枚舉出時(shí),為 true俺陋。
  • 【get】獲取該屬性的訪問器函數(shù)(getter)豁延。如果沒有訪問器, 該值為undefined腊状。
  • 【set】獲取該屬性的設(shè)置器函數(shù)(setter)诱咏。如果沒有設(shè)置器,該值為undefined缴挖。(僅針對(duì)包含訪問器或設(shè)置器的屬性描述有效)
    該方法能夠在IE8及以上的瀏覽器上運(yùn)行袋狞。

Object.getOwnPropertyNames(obj)

該方法返回obj上所有自身可枚舉和不可枚舉的屬性(不包括原型鏈上的屬性),如果傳入的obj不是數(shù)組映屋,則會(huì)報(bào)錯(cuò)硕并。該方法的兼容IE9及以上的瀏覽器。

Object.getPrototypeOf(obj)

該方法返回對(duì)象的原型對(duì)象秧荆,如果沒有的話倔毙,則返回null。需要指出的是乙濒,對(duì)于函數(shù)對(duì)象陕赃,其返回的并不是顯式原型(prototype)卵蛉,而是隱式原型(__proto__),該方法兼容IE9及以上的瀏覽器么库。

Object.is(val1,val2)

該方法是確定兩個(gè)值是否是相同的值傻丝,這個(gè)方法與===相比,其會(huì)將-0和+0看成不等诉儒,并且對(duì)于兩個(gè)NaN的比較葡缰,Object.is()也會(huì)看成是不等的。以下是Object.is()的示例:

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

該方法在微軟公司出的瀏覽器上只支持EDGE瀏覽器忱反。不過泛释,萬幸的是MDN提供了相應(yīng)的解決方案。

if (!Object.is) {
  Object.is = function(x, y) {
    if (x === y) { 
      return x !== 0 || 1 / x === 1 / y;
    } else {
      return x !== x && y !== y;
    }
  };
}

Object.preventExtensions()

該方法可以讓一個(gè)對(duì)象永遠(yuǎn)不能添加新的屬性温算,在嚴(yán)格模式下怜校,如果強(qiáng)行為對(duì)象添加屬性,會(huì)報(bào)錯(cuò)注竿,以下是Object.isExtensible()的注意事項(xiàng):

"use strict";
var obj = {name:"zhang"};
obj.name = "li"http://可以進(jìn)行修改
Object.preventExtensions(obj);
//obj.age = 14;嚴(yán)格模式下會(huì)報(bào)錯(cuò)
obj.__proto__.age = 13;
console.log(obj);//能夠在原型對(duì)象上添加屬性
obj.__proto__ = {}//不能直接重定義原型茄茁,會(huì)報(bào)錯(cuò)。

Object.seal(obj)

其對(duì)一個(gè)對(duì)象進(jìn)行密封巩割,并返回被密封的對(duì)象裙顽,這些對(duì)象都是不能夠添加屬性,不能刪除已有屬性宣谈,以及不能夠修改已有屬性的可枚舉型锦庸、可配置型、可寫性蒲祈。

Object.freeze(obj)

該方法將obj對(duì)象凍結(jié)甘萧,其任何屬性都是不可以被修改的。現(xiàn)在我們演示下這個(gè)用法梆掸。

var obj = {name:"zhangsan",prop:{age:23,sex:"man"}};
Object.freeze(obj);
obj.name = "lisi";
console.log(obj.name);//"zhangsan
//我們使用Object.defineProperty()方法來修改屬性
Object.defineProperty(obj,'prop',{"age":32,sex:"female"});
console.log(obj.prop);
//{age: 23, sex: "man"}貌似還是不行扬卷,我們換種方式看看
Object.prop.age = 25;
console.log(Object.prop);
//{age: 25, sex: "man"}
//這個(gè)對(duì)象居然改變了,明明已經(jīng)凍結(jié)了酸钦,為什么起屬性還是可以發(fā)生變化

這就要說到Object.freeze(obj) 的特性了怪得,其只是一個(gè)淺凍結(jié)。何為淺凍結(jié)卑硫?淺凍結(jié)僅僅是對(duì)對(duì)象的一級(jí)屬性進(jìn)行凍結(jié)徒恋,像上面代碼中所演示的那樣,如果直接修改其name和prop屬性是不能被修改的欢伏。如果屬性也是一個(gè)對(duì)象的話入挣,那將不一樣了,直接對(duì)屬性中的屬性就行修改硝拧,如Object.prop.age = 25;一樣径筏,是可以修改的葛假。既然有淺凍結(jié),就一定有深凍結(jié)了滋恬,那怎么才能實(shí)現(xiàn)深凍結(jié)呢聊训?

//我們可以配合遞歸實(shí)現(xiàn)
Object.prototype.deepFreeze = Object.prototype.deepFreeze || function (o){
    var prop, propKey;
    Object.freeze(o); // 首先凍結(jié)第一層對(duì)象
    for (propKey in o){
        prop = o[propKey];
        if(!o.hasOwnProperty(propKey) || !(typeof prop === "object") || Object.isFrozen(prop)){
            continue;
        }
        deepFreeze(prop); // 遞歸
    }
}

可以有人會(huì)對(duì)preventExtensions,seal,freeze這三個(gè)方法產(chǎn)生疑問,這三個(gè)方法對(duì)從擴(kuò)展恢氯、密封和凍結(jié)三個(gè)方面對(duì)對(duì)象進(jìn)行讀寫狀態(tài)的控制带斑,防止對(duì)象被改變。其中最弱的一層是preventExtensions勋拟,只能讓對(duì)象無法添加新的屬性勋磕,其次是seal,該方法無法添加屬性指黎,也無法刪除屬性,最后是freeze州丹。當(dāng)然醋安,上面這三種方法還是可以通過改變對(duì)象的原型對(duì)象,來增加原型鏈上的屬性墓毒,并且都使淺凍結(jié)吓揪。有對(duì)對(duì)象進(jìn)行控制的方法,就肯定有判斷其是否被控制的方法所计,Object.isExtensible()柠辞、Object.isSealed()Object.isfreeze(obj)。這三個(gè)是判斷是否被控制主胧,在此就不再贅述叭首。

Object.keys(obj)

該方法會(huì)返回obj上所有可以進(jìn)行枚舉的屬性的字符串?dāng)?shù)組,如下所示:

//數(shù)組對(duì)象
var arr  =[3,4,5];
console.log(Object.keys(obj))
//[0,1,2]
var obj = {}
console.log(Object.keys(obj))
//[],其不會(huì)遍歷原型鏈上的屬性踪栋。

該方法兼容IE9及以上的瀏覽器焙格,但是有相應(yīng)的解決方法。

if (!Object.keys) {
  Object.keys = (function () {
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
        dontEnums = [
          'toString',
          'toLocaleString',
          'valueOf',
          'hasOwnProperty',
          'isPrototypeOf',
          'propertyIsEnumerable',
          'constructor'
        ],
        dontEnumsLength = dontEnums.length;
    return function (obj) {
      if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
      var result = [];
      for (var prop in obj) {
        if (hasOwnProperty.call(obj, prop)) result.push(prop);
      }
      if (hasDontEnumBug) {
        for (var i=0; i < dontEnumsLength; i++) {
          if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
        }
      }
      return result;
    }
  })()
};

getOwnPropertySymbols(obj)

該方法返回obj對(duì)象上自身的(非繼承的)所有Symbol屬性鍵夷都。

Object.entries()眷唉、Object.getOwnPropertyDescriptors()、Object.values()這些方法還只是處于試驗(yàn)階段的囤官,所以不在這里進(jìn)行展開冬阳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市党饮,隨后出現(xiàn)的幾起案子肝陪,更是在濱河造成了極大的恐慌,老刑警劉巖刑顺,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件见坑,死亡現(xiàn)場(chǎng)離奇詭異嚷掠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)荞驴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門不皆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人熊楼,你說我怎么就攤上這事霹娄。” “怎么了鲫骗?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵犬耻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我执泰,道長(zhǎng)枕磁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任术吝,我火速辦了婚禮计济,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘排苍。我一直安慰自己沦寂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布淘衙。 她就那樣靜靜地躺著传藏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪彤守。 梳的紋絲不亂的頭發(fā)上毯侦,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音具垫,去河邊找鬼叫惊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛做修,可吹牛的內(nèi)容都是我干的霍狰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼饰及,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蔗坯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起燎含,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤宾濒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后屏箍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绘梦,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡橘忱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了卸奉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钝诚。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖榄棵,靈堂內(nèi)的尸體忽然破棺而出凝颇,到底是詐尸還是另有隱情,我是刑警寧澤疹鳄,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布拧略,位于F島的核電站,受9級(jí)特大地震影響瘪弓,放射性物質(zhì)發(fā)生泄漏垫蛆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一腺怯、第九天 我趴在偏房一處隱蔽的房頂上張望袱饭。 院中可真熱鬧,春花似錦瓢喉、人聲如沸宁赤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至愕够,卻和暖如春走贪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惑芭。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工坠狡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人遂跟。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓逃沿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親幻锁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子凯亮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 10,975評(píng)論 6 13
  • 1.屬性的簡(jiǎn)潔表示法 允許直接寫入變量和函數(shù) 上面代碼表明,ES6 允許在對(duì)象之中哄尔,直接寫變量假消。這時(shí),屬性名為變量...
    雨飛飛雨閱讀 1,136評(píng)論 0 3
  • 此文章用于歸納Object的所有方法 在JavaScript中岭接,object是所有對(duì)象的基礎(chǔ)(原型鏈的頂端)富拗,所以...
    moonburn閱讀 653評(píng)論 0 5
  • 首發(fā)于segmentfault:JavaScript 對(duì)象所有API解析 之前看到【深度長(zhǎng)文】JavaScript...
    若川i閱讀 429評(píng)論 0 1
  • 老師問弟子:一滴水如何能不干枯啃沪?弟子沉默不語粘拾。老師說道:一滴水,風(fēng)可以將它吹干谅阿、土可以把它吸干半哟、太陽可以把它蒸...
    上善若水_張建國(guó)閱讀 660評(píng)論 2 1