在面向?qū)ο蠹昂瘮?shù)編程語(yǔ)言中,不可變對(duì)象是一種對(duì)象。在被創(chuàng)造之后,它的狀態(tài)就不可以被改變。狀態(tài)可以被改變的對(duì)象,則被稱為可變對(duì)象。
這里狀態(tài)可以簡(jiǎn)單理解為對(duì)象的值。
在javascript中,原始值(undefined, null, 布爾值, 數(shù)字和字符串)這些都是不可變?cè)贾怠?br> 理解:不可變說(shuō)的是一旦這些基本類型值創(chuàng)建后會(huì)一直保存其內(nèi)存地址,直到被瀏覽器的垃圾回收機(jī)制回收。而我們一直用的創(chuàng)建一個(gè)字符串變量,只是將這個(gè)變量指向了該字符串的內(nèi)存地址,當(dāng)改變?cè)撟兞康闹?,也就是改變了該變量指向的字符串?nèi)存地址,而原來(lái)的字符串還在內(nèi)存中存在。
js對(duì)象的屬性值發(fā)生改變,會(huì)創(chuàng)建一個(gè)新的屬性值,然后改變的是該屬性指向的內(nèi)存地址。對(duì)象本身的內(nèi)存地址是沒(méi)有改變的。這樣對(duì)象的內(nèi)存地址沒(méi)有變化。
原始值:任何方法都無(wú)法更改一個(gè)原始值。
示例:
let s = 'hello'; // 這里申請(qǐng)內(nèi)存,并保存數(shù)據(jù)hello,并把內(nèi)存地址賦給
s.toUpperCase(); // 生成一個(gè)新的數(shù)據(jù)HELLO,并申請(qǐng)內(nèi)存保存之
s = s.toUpperCase(); // 把新的內(nèi)存地址賦給s,此時(shí)s的值就是HELLO了。原來(lái)的'hello'會(huì)被回收。
一、js數(shù)據(jù)
1.typeof
-
typeof返回一個(gè)字符串,指示未經(jīng)計(jì)算操作數(shù)的類型。 -
typeof能區(qū)分值類型的詳細(xì)類型,但對(duì)于引用類型就不行了。 -
typeof null返回object是歷史遺留問(wèn)題,自從js出現(xiàn)就是這樣的。 -
typeof通常只返回6種數(shù)據(jù)類型:number,string,boolean,undefined,object,function,symbol
js的typeof數(shù)據(jù)類型.png
2.instanceof
instanceof 運(yùn)算符用來(lái)測(cè)試一個(gè)對(duì)象在其原型鏈中是否存在一個(gè)構(gòu)造函數(shù)的 prototype 屬性。
語(yǔ)法:
// obj是使用構(gòu)造函數(shù)構(gòu)造的變量,Object是構(gòu)造函數(shù)的名稱
obj instanceof Object


3.字面量創(chuàng)建變量和new 構(gòu)造函數(shù)創(chuàng)建變量
什么是字面量?
兩者區(qū)別:
- 字面量創(chuàng)建對(duì)象
let obj = { id: 1, };
let str = 'abc';
let num = 123;
上面創(chuàng)建變量時(shí),不會(huì)調(diào)用構(gòu)造函數(shù)。是一個(gè)原始類型(基本類型)的值。
使用new后,會(huì)將原始數(shù)據(jù)類型轉(zhuǎn)為對(duì)象。
- 構(gòu)造函數(shù)創(chuàng)建變量
let obj = new Object({ id:1 });
let str = new String('abc');
let num = new Number(123);
new方式創(chuàng)建變量的本質(zhì)是方法調(diào)用,會(huì)遍歷__proto__中的方法和屬性,找到該構(gòu)造函數(shù)的方法,然乎生產(chǎn)方法調(diào)用必須的堆棧信息,方法調(diào)用結(jié)束后,還要釋放堆棧,性能不如字面量方式。
問(wèn)題:
- 字面量方式創(chuàng)建的變量,為什么有構(gòu)造函數(shù)函數(shù)創(chuàng)建的變量的方法和屬性?
可以參考這個(gè)問(wèn)題
涉及到包裝類型。
發(fā)現(xiàn)一個(gè)有趣的:
image.png
4.原型
-
原型對(duì)象:這個(gè)原型對(duì)象包含所有實(shí)例共享的屬性和方法。其實(shí)最初指的是函數(shù)的prototype。
image.png 當(dāng)使用構(gòu)造函數(shù)實(shí)例化時(shí),實(shí)例化后的是對(duì)象,會(huì)將實(shí)例化對(duì)象的
__proto__指向構(gòu)造函數(shù)的prototype。任意一個(gè)
函數(shù)(包括構(gòu)造函數(shù))都有一個(gè)prototype屬性。函數(shù)也是對(duì)象。所有
對(duì)象都有__proto__屬性。構(gòu)造函數(shù)實(shí)例化后的是一個(gè)對(duì)象。
自己理解示例:
let str = new String('abc')
一、str.__proto__
1. str.__proto__是對(duì)象,沒(méi)有prototype。
2. str.__proto__指向(或繼承)構(gòu)造函數(shù)String的String.prototype。

二、String.prototype
1. String.prototype包含構(gòu)造函數(shù)String自定義的屬性和方法。String.prototype還包含構(gòu)造器constructor和__proto__。
1.1 String.protype.constructor指向本身的函數(shù)String

1.2 String.prototype.__proto__:因?yàn)?code>String.protype.是對(duì)象,下面無(wú)構(gòu)造函數(shù)了,所以String.prototype.__proto__指向的是對(duì)象的原型prototype。對(duì)象指的不是Object,Object是函數(shù)。

新建函數(shù)時(shí),函數(shù)的
prototype下的__proto__指向的是對(duì)象的原型prototype。
新建的對(duì)象沒(méi)有prototype屬性。
三、String.__proto__
1. String.__proto__指向的是構(gòu)造函數(shù)String的構(gòu)造函數(shù)Function的prototype,即Function.prototype。

四、Function.prototype
-
Function.protype.constructor指向本身的函數(shù)Function
image.png -
Function.prototype.__proto__:因?yàn)?code>Function.protype.是對(duì)象,下面無(wú)構(gòu)造函數(shù)了,所以Function.prototype.__proto__指向的是對(duì)象的原型prototype。
image.png
五、Function.__proto__
1. Function.__proto__指向Function.prototype。即 Function.__proto__和Function.prototype相等。所以Function.__proto__也指向的是對(duì)象的原型prototype。

5.原型鏈
- 由于
__proto__是任何對(duì)象都有的屬性,所以最終會(huì)形成一條__proto__連起來(lái)的鏈條,遞歸訪問(wèn)__proto__必須最終到頭,并且值是null。 - 當(dāng)js引擎查找對(duì)象的屬性時(shí),先查找對(duì)象本身是否存在該屬性,如果不存在,會(huì)在原型鏈上找,但不會(huì)查找自身的
prototype。
image.png - 給原型
prototype添加方法和屬性






