js - 萬(wàn)物皆對(duì)象!??
對(duì)于初學(xué)js的小白來(lái)說(shuō),js的對(duì)象無(wú)疑是令大家困惑的一個(gè)難點(diǎn),而面向?qū)ο蟮乃枷雲(yún)s是掌握js編程的核心。因此,想要學(xué)好js必須搞清楚什么是對(duì)象,什么是面向?qū)ο蟆?br> '萬(wàn)物皆對(duì)象',這句話可能對(duì)很多學(xué)習(xí)js的人來(lái)說(shuō)都不陌生,但是js中真的是'萬(wàn)物皆對(duì)象'嗎?接下來(lái)我們就來(lái)聊聊這件事吧~
js - 數(shù)據(jù)類(lèi)型
js中將數(shù)據(jù)分為七種類(lèi)型
- String
- Number
- Boolean
- Null
- Undefined
- Symbol
- Object
如果對(duì)這七種數(shù)據(jù)類(lèi)根據(jù)是否是對(duì)象系統(tǒng)再劃分,又可分為兩大類(lèi)。前六種數(shù) 據(jù)類(lèi)型為非對(duì)象系統(tǒng)(基本數(shù)據(jù)類(lèi)型),最后一種為對(duì)象系統(tǒng)(Array,Map,Set,Function,Object)。
至于為何如此劃分,還需要從值類(lèi)型和引用類(lèi)型聊起...
- 1.值類(lèi)型
存儲(chǔ)在棧區(qū)的數(shù)據(jù),無(wú)法添加、刪除屬性,如果直接賦值給另一個(gè)變量,兩個(gè)變量互不影響,修改其中任意一個(gè)變量的值,都對(duì)另一個(gè)變量的值無(wú)影響。
舉例:
var str = "李四";
//無(wú)法添加屬性
str.name = "字符串";
//打印 undefined 屬性沒(méi)有添加上
console.log(str.name)
//將str的值賦給變量str2
var str2 = str;
//修改str2的值
str2 = "張三";
//打印 "李四" str的值不變
console.log(str)
結(jié)論:String,Number,Boolean,Null,Undefined,Symbol都屬于值類(lèi)型。
- 引用類(lèi)型
引用類(lèi)型的值存儲(chǔ)在堆區(qū),在棧區(qū)里存放對(duì)堆區(qū)數(shù)據(jù)的引用地址。如果直接賦值給另一個(gè)變量,其實(shí)是把數(shù)據(jù)的存放地址拷貝給了另一個(gè)變量,兩個(gè)變量擁有同一個(gè)地址,共享同一份數(shù)據(jù),任何一方更改數(shù)據(jù),都會(huì)導(dǎo)致另一方數(shù)據(jù)發(fā)生改變。
舉例:
var arr = [1,2,3];
//添加屬性
arr.name = "score";
//打印 "score" 屬性添加成功
console.log(arr.name)
//刪除屬性
delete arr.name;
//打印 undefined 屬性刪除成功
console.log(arr.name)
//將arr的值賦值給另一個(gè)變量
var arr2 = arr;
//修改其中一個(gè)變量的值
arr2[0] = 4;
//打印 [4,2,3] 數(shù)據(jù)改變
console.log(arr);
//打印 [4,2,3] 數(shù)據(jù)改變
console.log(arr2);
結(jié)論:基本數(shù)據(jù)類(lèi)型除外的(Array,Map,Set,Object,Date...)都屬于引用類(lèi)型
js-什么是對(duì)象?
概括講:
對(duì)象就是屬性和方法的集合
,結(jié)合上面的結(jié)論,值類(lèi)型無(wú)法添加屬性和方法,因此不滿足對(duì)象的定義。而引用類(lèi)型都可以設(shè)置屬性和方法。
結(jié)論:引用類(lèi)型的數(shù)據(jù)都是對(duì)象,換言之,非值類(lèi)型的其它數(shù)據(jù)類(lèi)型都是對(duì)象。個(gè)人理解js中"萬(wàn)物皆對(duì)象的"真正含義即:js中除了六種值類(lèi)型以外的所有數(shù)據(jù)類(lèi)型都是對(duì)象。
js-對(duì)象的創(chuàng)建方式
- 字面量
- Object函數(shù)
- 工廠模式
- 構(gòu)造函數(shù)
1.
字面量
var obj = {"name":"張三",age:10,say:function({} }
Object
var obj = new Object();
obj.name = "張三";
obj.say = function(){};
工廠模式
function people(){
var obj = new Object();
obj.name = "張三";
obj.say = function(){
console.log("你好")
}
var p1 = people();
構(gòu)造函數(shù)模式
function People(){
this.name = "張三";
this.say = function(){
console.log("你好")
}
}
var p1 = new People();
- prototype 、constructor、 _proto _
prototype(顯式原型)
每一個(gè)函數(shù)都有一個(gè)默認(rèn)的屬性prototype,稱(chēng)之為原型。原型本身就是一個(gè)對(duì)象,可以設(shè)置屬性和方法,默認(rèn)帶有一個(gè)屬性constructor。通過(guò)原型設(shè)置的屬性和方法能夠被實(shí)例對(duì)象擁有,也可以用來(lái)實(shí)現(xiàn)繼承。constructor(構(gòu)造器)
存在于函數(shù)的prototype(原型)中,實(shí)質(zhì)就是指向構(gòu)造函數(shù)的指針,或者說(shuō)它的值就是原型所在的函數(shù)。_proto_(隱式原型)
每一個(gè)實(shí)例對(duì)象默認(rèn)的隱式屬性,指向創(chuàng)建這個(gè)對(duì)象的函數(shù)的原型,或者簡(jiǎn)單理解為與prototype的值一樣。一般不上場(chǎng),交由prototype處理屬性的增刪改查。所以?xún)烧哧P(guān)系可以概括為臺(tái)前(prototype)幕后(_ proto_)。
- 總結(jié):
1.任何一種對(duì)象的創(chuàng)建方式其實(shí)內(nèi)部都是通過(guò)函數(shù)來(lái)實(shí)現(xiàn)的;
2.每一個(gè)函數(shù)都會(huì)在生成的時(shí)候擁有一個(gè)默認(rèn)的原型屬性(prototype),如果把這個(gè)函數(shù)作為類(lèi)來(lái)理解,prototype里存放的就是類(lèi)的共同屬性特征(eg:人類(lèi)都有鼻子眼睛嘴巴,會(huì)行走)。
3.每一個(gè)原型(prototype)中都有一個(gè)默認(rèn)constructor屬性,用來(lái)獲取原型存在的函數(shù)。
4.每一個(gè)創(chuàng)建出來(lái)的實(shí)例對(duì)象(eg:張三),都會(huì)擁有默認(rèn)的隱式屬性proto,指向prototype。所以只要是prototype中有的屬性,proto都擁有,因此每個(gè)實(shí)例對(duì)象都擁有(eg:張三擁有人類(lèi)的所有共同特征)
js-繼承
1.類(lèi)式繼承
實(shí)現(xiàn)
在子類(lèi)函數(shù)內(nèi)部,使用call()、apply()、bind()改變父類(lèi)內(nèi)部this指向,指向子類(lèi)創(chuàng)建的實(shí)例。例子:
//父類(lèi)
function People(name,age){
this.name = name;
this.age = age;
}
//原型方式設(shè)置共有屬性
People.prototype.eyes = "眼睛";
//子類(lèi)
function Teacher(name,age){
//方法一: call()
People.call(this,name,age)
//方法二: apply()
<!--
People.apply(this,[name,age])
-->
//方法三: bind()
<!--
var fuc = People.bind(this,name,age);
fuc()
-->
tips:
1.call和apply區(qū)別在于apply的第二個(gè)參數(shù)必須是數(shù)組類(lèi)型,所有傳的參數(shù)必須存放在數(shù)組中。
call的可以是任意類(lèi)型,但是參數(shù)需要單獨(dú)傳遞。
2.bind的參數(shù)和call的一致,但call和apply都是立即執(zhí)行, bind是返回一個(gè)函數(shù),需要調(diào)用函數(shù)后執(zhí)行。
}
var tea = new Teacher("老陳",26)
//{name:"老陳",age:26}
console.log(tea);
//{}
console.log(Teacher.prototype)
缺點(diǎn):不是真正的繼承,子類(lèi)不能擁有父類(lèi)原型的屬性。
子類(lèi)原型沒(méi)有繼承父類(lèi)的屬性,不能實(shí)現(xiàn)復(fù)用。
優(yōu)點(diǎn):可以向父類(lèi)傳遞參數(shù)
2.原型式繼承
實(shí)現(xiàn):將父類(lèi)的實(shí)例賦值給子類(lèi)的原型。
例子:
//父類(lèi)
function People(){
this.name = "張三"
}
People.country = "中國(guó)";
//子類(lèi)
function Teacher(){
}
Teacher.prototype = new People();
var tea = new Teacher();
//{name:"張三",country:"中國(guó)"}
console.log(tea)
//{country:"中國(guó)"}
console.log(Teacher.prototype)
缺點(diǎn):不能在創(chuàng)建子類(lèi)實(shí)例時(shí)向父類(lèi)傳參
優(yōu)點(diǎn):子類(lèi)的原型能夠擁有父類(lèi)原型以及實(shí)例的屬性,可以復(fù)用
3.組合式繼承
實(shí)現(xiàn):原型式+組合式
例子:
//父類(lèi)
function People(name,age){
this.name = name;
this.age = age;
}
People.country = "中國(guó)";
//子類(lèi)
function Teacher(name,age){
People.call(this,name,age)
}
Teacher.prototype = new People();
var tea = new Teacher("老陳",26);
//{country:"中國(guó)",name:"老陳",age:26}
console.log(tea)
//{country:"中國(guó)"}
console.log(Teacher.prototype)
優(yōu)點(diǎn):既能向父類(lèi)傳參,又能繼承父類(lèi)原型的屬性,實(shí)現(xiàn)真正意義上的繼承,可復(fù)用。