說(shuō)說(shuō)對(duì)象那些事兒,(屬性行為,原型鏈)

聲明 本文僅用于學(xué)習(xí)交流,切勿用作其他用途。

[TOC]


js 本來(lái)是沒(méi)有對(duì)象的,不知道是不是因?yàn)閱紊砭昧?,所以被迫有了?duì)象。


對(duì)象創(chuàng)建

對(duì)象創(chuàng)建一般我們都是通過(guò)new function來(lái)的,Es6中可以直接寫(xiě)class,這樣子用法就是new一個(gè)class了。
當(dāng)然也可以使用Object.create 和 Object.assign

對(duì)象的屬性行為,這可是很有意義的


說(shuō)到這個(gè)屬性行為呀,我想起了基礎(chǔ)數(shù)據(jù)類(lèi)型的Symbol,以這個(gè)Symbol作為key值的對(duì)象,通過(guò)for...in 是拿不到這個(gè)Symbol的,不信大可以試試如下代碼

    var smb = Symbol("key1");
    var a = {};
    a[smb] = "hello wolrd";

    console.log(Object.keys(a)) ;//看看這里是不是打印的[]就知道啦

    //之前說(shuō)過(guò)哦,要通過(guò)Object.getOwnPropertySymbols才能拿到哦
    console.log(Object.getOwnPropertySymbols(a)) ;//[Symbol(key1)]

對(duì)于對(duì)象的屬性行為,目前有 configurable,writable,enumerable,value

這個(gè)屬性行為,其實(shí)說(shuō)白了,和c++成員私有公有差不多的感覺(jué),對(duì)于大家使用 Object.defineProperty的情況我不是很清楚,但是至少在我看到 '怎么在Es5中定義常量' 之前我是沒(méi)怎么使用的,都是用已有的一些類(lèi)呀什么直接拿過(guò)來(lái)用,或者直接把類(lèi)當(dāng)做hashMap來(lái)用...


定義常量

    //瀏覽器下面可以用下述方法設(shè)置常量。
    function setConst(name,value,log){
        (log === undefined) && (log = true);
        if(typeof name == 'string' && !name){
            if( !window.hasOwnProperty(name)){
                Object.defineProperty(window,name,{
                    configurable:false,//避免用defineProperty修改
                    writable:false,//不可寫(xiě)入
                    value:value
                })
            }else{
                log && console.warn("const variable name",name,"already exists")
            }
        }else{
            log && console.warn("name",name," is illegal")
        }
    }

    //useage
    setConst("Five",5);
    console.log(Five);//5
    setConst("Five",6);
    console.log(Five);//5
    Five = 7;
    console.log(Five);//5

如上所示,js可以設(shè)置類(lèi)的可寫(xiě)屬性,枚舉屬性,是否可以修改對(duì)象屬性的屬性,以及值。

configurable

為false的時(shí)候,delete,defineProperty操作無(wú)效

writable

為false的時(shí)候 字面意思,不可更改,重新賦值無(wú)效

enumerable

為 false時(shí),不出現(xiàn)在枚舉列表,即Object.keys() 不能拿到對(duì)應(yīng)的key

value

默認(rèn) undefined ,如字面意思,值


對(duì)象創(chuàng)建方式

  • new function
  • Object的操作,如Object.assign ,Object.create
  • 直接以JSON的形式創(chuàng)建 --如 var a = { h:xxx }
  • new class --等價(jià)于new function

new function

    function T(){

    }


    var t = new T();//new function的時(shí)候返回的是一個(gè)類(lèi)

    var r = T();//這種情況就是執(zhí)行一個(gè)function,沒(méi)有new就是普通執(zhí)行


    //----------------------------------------------------
    function F(){
        (typeof this != 'undefined') && (this.t = "hello");
        //如果這里沒(méi)有返回或者返回不是對(duì)象,那么使用new的時(shí)候就返回this對(duì)象,
        //如果這里返回了對(duì)象,那就不會(huì)返回this了

        ///////////////////////////////////////////////////
        var t = {t:"test"};
        return t;//這樣寫(xiě)就是在玩火。不管怎么new,都是返回{t:"test"}這個(gè)對(duì)象,雖然引用不一樣
        ///////////////////////////////////////////////////
    }
    var t = new F();//或者F() 
    console.log(t.t);//‘test’



    //----------------------------------------------------
    function G(){
        if(new.target){ //我們可以這樣檢驗(yàn)調(diào)用的時(shí)候是否使用了new
            //....
        }
    }


Object的操作

Object.creat方法創(chuàng)建一個(gè)新對(duì)象,使用現(xiàn)有的對(duì)象來(lái)提供新創(chuàng)建的對(duì)象的proto。 ;

Object.assign 方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象。它將返回目標(biāo)對(duì)象。

    //////////////////
    var b = {k:1,k2:2};
    var a  = Object.create(b);//這里會(huì)創(chuàng)建對(duì)象a,把b作為a的原型,
    console.log(a.k,a.k2,a.__proto__ == b)
    b.k = 3,b.k2 = 4;
    console.log(a.k,a.k2);// 3,4

    var c  = Object.create(a,{
        key1:{
            value: "this is a test case", 
            writable: true,
            enumerable: false,
            configurable: true 
        },
        key2:{
            value: "this is read-only value", 
            writable: false,
            enumerable: true,
            configurable: true 
        }
    });//這里會(huì)把a(bǔ)作為c的原型,并且增加val屬性,該屬性的行為可以自行定義
    
    console.log(c,c.key1 ) ;
    console.log(c.k,c.k2);//3,4 這個(gè)就涉及到了原型鏈了

    

    /////////////////////
    var d = Object.assign(c,{k:6,k2:5},undefined,5,null,"hello",{});
    console.log(d) ;// {k:6,k2:5,'0': 'h', '1': 'e', '2': 'l', '3': 'l', '4': 'o'}
    //MDN上面說(shuō) 原始類(lèi)型會(huì)被包裝,null 和 undefined 會(huì)被忽略。只有字符串的包裝對(duì)象才可能有自身可枚舉屬性

    //拷貝的是引用地址值來(lái)著。原型鏈中的和不可枚舉的都不能拷貝。返回值是目標(biāo)對(duì)象,也就是如下
    console.log(c == d);//true


直接以JSON的形式創(chuàng)建

    //////////////////
    var a = {
        key1:"1",
        key2:2,
        key3:false,
        func4:function(){
            return this.key1;
        }
    }

    console.log(a.func4())

    var b = JSON.parse('{ "t":1,"k":"hello","m":"world"} ')
    console.log(b);//{ t: 1, k: 'hello', m: 'world' }

new class

    //////////////////
    class cls{

        set key1(val){
            this._key1 = val;
        }
        get key1(){
            return this._key1;
        }

        constructor(){
            this._key1 = "test";
        }
    }
    var a = new cls();

    //相當(dāng)于 
    //function cls(){ this._key1 = "test" };
    //var a = new cls();
    //Object.defineProperty(a,"key1",{
    //set:function(v){ this._key1 = v},get:function(){ return this._key1}
    //})

原型鏈與繼承

參照 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

原型鏈

關(guān)于這個(gè)原型鏈我的理解有些不到位,歡迎大家指出我的錯(cuò)誤的理解,

我的理解大概就是原型鏈就是對(duì)象的一個(gè)查找表,類(lèi)似lua的原表,當(dāng)我們?cè)噲D obj['key1'] 時(shí),會(huì)先在obj下查找key1是否存在,沒(méi)找到的情況再去 obj.__proto__ 去查找,如果還沒(méi)找到則去 obj.__proto__.__proto__ 去查找,依次類(lèi)推,直到找到或者遍歷完原型鏈。

這個(gè)查找的概念就是在使用 obj['key'] 或者 obj.key 時(shí)執(zhí)行的查找。

    var a = { b :1,c:"2"  }
    var b = Object.create(a);//創(chuàng)建對(duì)象,指定對(duì)象的原型是a,
    console.log(b);//{}
    console.log(b.b,b.c);//這里在b里面沒(méi)找到b和c屬性,所以去原型鏈找
    console.log(b.__proto__ == a);//true

所以我對(duì)原型鏈的理解為:對(duì)象所具有的默認(rèn)值,修改原型鏈中的這個(gè)值(__proto__.xxx)會(huì)影響具有相同原型鏈的其他對(duì)象,但是在自身增加對(duì)象則會(huì)覆蓋這個(gè)值,如下

  function T(){

  }
  T.prototype.test = 1;

  var t1 = new T(),t2 = new T();;
  console.log(t1.test,t2.test);//1,1
  t1.__proto__.test = 2;
  console.log(t1.test,t2.test);//2,2
  t2.test = "hello";
  console.log(t1.test,t2.test);//2,hello

繼承

這個(gè)是個(gè)大問(wèn)題,畢竟js不是面向?qū)ο蟮?/code>,所以感覺(jué)原型鏈很大一部分感覺(jué)是為了繼承而生的。

其操作大概就是 childCls.prototype = parent

我們用Object.create來(lái)創(chuàng)建對(duì)象的時(shí)候,實(shí)際上就是一個(gè)繼承了。只是有時(shí)候可能沒(méi)有那么明確,上面的原型鏈中的數(shù)據(jù),也就是說(shuō)繼承之后的初始值,我們可以在繼承之后去更改這些值。這個(gè)繼承給人的感覺(jué),很隱蔽。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 什么是原型語(yǔ)言 只有對(duì)象,沒(méi)有類(lèi);對(duì)象繼承對(duì)象,而不是類(lèi)繼承類(lèi)。 “原型對(duì)象”是核心概念。原型對(duì)象是新對(duì)象的模板,...
    zhoulujun閱讀 2,441評(píng)論 0 12
  • JS中原型鏈,說(shuō)簡(jiǎn)單也簡(jiǎn)單。 首先明確: 函數(shù)(Function)才有prototype屬性,對(duì)象(除Object...
    前小白閱讀 4,066評(píng)論 0 9
  • ??面向?qū)ο螅∣bject-Oriented,OO)的語(yǔ)言有一個(gè)標(biāo)志,那就是它們都有類(lèi)的概念,而通過(guò)類(lèi)可以創(chuàng)建任意...
    霜天曉閱讀 2,252評(píng)論 0 6
  • 兒時(shí) 對(duì)山那邊的世界感到好奇如今明白 山那邊一直住在心里攀上一座座山就是邁過(guò)心里的一道道坎一次次站在山頂對(duì)靈魂一次...
    翊寒閱讀 888評(píng)論 8 19
  • 時(shí)間過(guò)得很快,一年光景就這樣過(guò)去了,又一年新生在9月10號(hào)這一天如約而至。過(guò)去的一年作為小師妹在師兄師姐的關(guān)照下成...
    曉娟啊閱讀 216評(píng)論 0 0

友情鏈接更多精彩內(nèi)容