開篇廢話是一種情懷
在我們開始學(xué)習(xí)面向?qū)ο笾埃紫鹊孟认胍粋€問題,那就是何為對象?
- 在日常生活中我們有男朋友\女朋友,稱之為對象。有了男朋友可以為你遮風(fēng)擋雨,有了女朋友可以為你洗衣做飯,同理,在我們的二進(jìn)制編程世界里,對象完全可以理解為工具或者工具包,當(dāng)然,在某種特定情況下,我們也可以把人比作是工具。
- 面向?qū)ο缶幊唐鋵嵤且环N思想、思維的轉(zhuǎn)變,從面向過程轉(zhuǎn)變成面呈對象。面向過程注重的是過程,而面向?qū)ο笞⒅氐氖墙Y(jié)果,兩者的目的相同,但是實現(xiàn)方式卻不盡相同。
- 據(jù)說,面向?qū)ο笏季S最早是一個生物學(xué)家提出來的,他說:"我們編寫的代碼就好比生物的每一個細(xì)胞,我們的身體的每一個組件都代表一個工具,手供我們吃飯,腿供我們行走,不管那天手不能用了,但它不會影響腳的行走,如果能把每一類型的代碼抽取成一個一個的工具,好比,鉗子、鑷子、錘子,那我們對代碼、對工具的管理就會顯得非常方便,只需要將這一類工具放到一個工具包里面即可。”
- 天了嚕,廢話不多說了,好像開篇廢點話,是一種習(xí)慣!下面就讓我們開始認(rèn)識面向?qū)ο缶幊獭?/li>
- 學(xué)習(xí)面向?qū)ο笾埃孟劝严旅孢@些東西搞明白!
Js語言的回顧
-
三個組成部分
- BOM:全稱Browser Object Model 瀏覽器對象模型,核心對象(window loacation);
- DOM:Document Object Model 文檔對象模型,DOM樹,本身為我們操作頁面元素提供了一套方法(API),API:application programming interface 應(yīng)用程序編程接口
- ECMAScript:規(guī)定js的核心語法,js語句,關(guān)鍵字,保留字
-
數(shù)據(jù)類型
- 基本數(shù)據(jù)類型(簡單數(shù)據(jù)類型)
string 字符串類型
number 數(shù)值
boolean 布爾類型(true | false)
undefined 未定義
null 空(對象) 這個類型有點特殊- 復(fù)雜數(shù)據(jù)類型(復(fù)合數(shù)據(jù)類型)
Object 對象類型
Array 數(shù)組類型
Funcation 函數(shù)類型
Date 日期類型
String 對象
Number
Boolean**判斷數(shù)據(jù)類型的關(guān)鍵字是 typeof **
注意:
復(fù)雜數(shù)據(jù)在使用typeof操作的時候,打印出來的結(jié)果都是object ,除了函數(shù)等于和全等
賦值(=)
等于符號(==):比較的時候只判斷數(shù)值是否是相等的
全等符號(===):比較的時候不僅要比較數(shù)據(jù)還需要比較類型
不等于(!=)
不全等于(!==)關(guān)系運算符
返回值:布爾類型,要么是true要么是false
大于 >
小于 <
大于等于 >=
小于等于 <=
- 邏輯運算符(重點)
- 邏輯非( ! ) 取反
- 邏輯或( || )
>**語法:表達(dá)式1 || 表達(dá)式2
結(jié)果:
判斷表達(dá)式1,如果表達(dá)式1為真,那么就返回表達(dá)式
如果表達(dá)式1的值為假,那么就返回表達(dá)式2**
- **邏輯與(&&)**
>**語法:表達(dá)式1 && 表達(dá)式2
結(jié)果:
如果表達(dá)式1為真,返回表達(dá)式2
如果表達(dá)式1為假,返回表達(dá)式1**
- **返回值是表達(dá)式,而不是布爾值**
- 值類型和引用類型(重點)
- 值類型
>**string
number
boolean
undefined
值類型:存儲的是具體的值
賦值:
1.把右邊變量存儲存儲的值(具體的數(shù)據(jù))復(fù)制一份給左邊的變量
2.值類型的賦值,是簡單數(shù)據(jù)的復(fù)制,他們保存在相對獨立的空間中,彼此不會影響
**
- 引用類型
>**object類型
引用類型:存儲的是指向具體值得地址(引用)
賦值:
1.把右邊變量存儲存儲的值(指向具體數(shù)據(jù)的地址)復(fù)制一份給左邊的變量
2.引用類型賦值:修改了某個對象的屬性,對另外一個對象的屬性會有影響
**
- 在函數(shù)中的使用
值類型作為函數(shù)的參數(shù):
實參和形參他們的數(shù)據(jù)是相互獨立的
<script>
function func(param){
console.log(param); //我是字符串
param = "我也是一個字符串";
console.log(param);
}
var a = "我是字符串";
func(a);
console.log(a);
</script>
引用類型作為函數(shù)的參數(shù):
形參和實參共享同一份數(shù)據(jù),修改其中的某個對象對另外一個對象也會有影響
<script>
//02 引用類型作為函數(shù)的參數(shù)傳遞
var obj = {name:"小明"};
function funcName(param) {
param.name = "小王";
param = {
name:"張明明"
};
console.log(param.name); // 張明明
}
funcName(obj);
console.log(obj.name); // 小王
//
//
var arr1 = [1,2,3];
var arr2 = arr1;
console.log(arr1);
console.log(arr2);
//該行代碼切斷和arr1的關(guān)系,對象內(nèi)保存的地址指向了另外一塊內(nèi)存空間
arr1.push(4);
arr2 = [1,2,3];
console.log(arr1); //1,2,3,4
console.log(arr2); //1,2,3
</script>
- 對象的動態(tài)特性
- 已經(jīng)定義好的對象,我們對它進(jìn)行增刪改查的操作
- 訪問對象有兩種形式:
**
1.點語法
在使用點語法設(shè)置對象的屬性的時候,如果對象中不存在改屬性,就是增加操作
如果對象中已經(jīng)存在該屬性,那么就是修改操作
2.[ ] 中括號語法
對象:鍵 - 值(key-value)對的集合
注意點:在使用[]語法的時候,鍵應(yīng)該使用雙引用
**
in關(guān)鍵詞的使用
作用:
1.遍歷對象的key
2.判斷某個對象中是否存在指定的屬性語法
鍵 in 對象 返回值:布爾類型的值
注意點:在使用in關(guān)鍵字的時候,key是字符串,需要加上雙引號遍歷數(shù)組
遍歷對象 在這里必須使用[ ]語法不能直接使用點語法
在數(shù)組中索引是key ,數(shù)組的元素是value-
delete關(guān)鍵字
-
作用:
(1) 刪除對象中的屬性
(2) 刪除沒有使用var關(guān)鍵字聲明的全局變量
注意:
(1)返回值 布爾類型的值(我們可以通過該值來判斷是否刪除成功)
(2)使用var關(guān)鍵字聲明的變量無法被刪除
(3)刪除對象中不存在的屬性沒有任何變化,但是返回值為true
(4)不能刪除window下面的全局變量(使用var聲明),但是可以刪除直接定義在window上面的屬性
-
作用:
循環(huán)對象
for循環(huán)
while
do...while(至少會執(zhí)行一次)
for...in(主要用于遍歷對象)
-
函數(shù)的幾種創(chuàng)建
聲明函數(shù)
<script>
function 函數(shù)名稱 (形參1,形參2)
{
//函數(shù)體
}
//調(diào)用
//函數(shù)的名稱();
function funcName (){
}
</script>
函數(shù)表達(dá)式
<script>
//01 匿名函數(shù)
var func01 = function (){
};
//02 命名的函數(shù)表達(dá)式
var func02 = function func(){
};
</script>
使用構(gòu)造函數(shù)創(chuàng)建函數(shù)對象
<script>
var func = new Function(); //沒有內(nèi)容(沒有函數(shù)體)
func();
function funcTest (){}; //等價
var func02 = new Function("console.log('demo');");
func02();
</script>
<script>
var obj = {name:"zhangsan"};
var obj2 = new Object();
var obj3 = {};
</script>
回顧前面這些呢,就是想讓接下來看面向?qū)ο蟮臅r候,腦海中有個印象和回憶,當(dāng)然,這也是想到會有一些編程小白理解起來困難的原因。知識點有點枯燥,學(xué)編程嘛 得有點耐心才行.
面向過程 & 面向?qū)ο?/h3>
- 都是一種解決問題的思路(思想)
- 面向過程在解決問題的時候,關(guān)注的是解決問題需要的一個接著一個的過程(步驟)
- 面向?qū)ο笤诮鉀Q問題的時候,關(guān)注的是解決問題所需要的對象.
- 舉例
就用洗衣服來形象的打個比方
如果你是用手洗的話,那就不得不考慮 倒水-搓衣服-加洗衣液-清水涮-手?jǐn)Q干-晾起來 這就是面向過程
但如果你忽略這些步驟 直接放洗衣機(jī)洗的話 可能都不用考慮晾干的步驟 這就是面向?qū)ο?/p>
什么是對象
- 對象的特征 (靜態(tài)的描述信息),比如:學(xué)號 - 性別 - 年齡 - 家庭住址 - 身高 - 體重 ... 等等
- 有的對象有行為 (動態(tài)的特征), 比如:吃飯 - 睡覺 - 開車 - 玩游戲 - 談戀愛
- 代碼示例
var zhangsan = {
name:"張三",
sex:"男",
age:18,
address:"天上人間1號公館",
eat:function () {
console.log('能吃');
},
sleep:function () {
console.log("能睡");
},
say:function () {
console.log("能說話");
},
run:function () {
console.log("能運動");
},
song:function () {
console.log("能唱歌");
}
};
//打印對象的屬性并調(diào)用相關(guān)的方法
console.log(zhangsan.name,zhangsan.age,zhangsan.address);
zhangsan.say();
zhangsan.sleep();
現(xiàn)實中的對象和編碼中的對象
- 靜態(tài)的描述信息:屬性
- 動態(tài)的行為特征:方法
- 面向?qū)ο蠛兔嫦蜻^程都是解決問題的一種方式(思想),沒有孰優(yōu)孰劣之分
- 面向?qū)ο蟊旧硎菍γ嫦蜻^程的封裝
為什么要使用面向?qū)ο缶幊?
- 更方便
- 復(fù)用性會更好
高內(nèi)聚和低耦合(電路)
冗余(重復(fù)的東西)-->封裝(提取相同的部分作為函數(shù)體,抽取不同的部分作為參數(shù))
js對象是由兩個對象組成的
- 一個叫構(gòu)造函數(shù)對象
- 一個叫原型對象
編程語言
- ** 匯編語言是對內(nèi)存的地址進(jìn)行編程的**
- ** C語言是第一款比較流行的面向過程語言 **
- ** C語言和面向?qū)ο笫蔷幊淌澜缫粋€劃時代的里程碑**
- ** 構(gòu)造函數(shù)和普通函數(shù)是一回事,只不過構(gòu)造函數(shù)是通過普通函數(shù)實現(xiàn)的**
面向?qū)ο蟮奶匦裕?/h5>
- 封裝
作用:方便代碼的維護(hù),提高代碼的復(fù)用性,更安全的訪問數(shù)據(jù)的方式
注意: js中的封裝多了一層意思,就是使用對象來封裝變量和函數(shù)
- 繼承
- 現(xiàn)實生活中的繼承:繼承遺產(chǎn),一個人獲得另一個人所擁有的財富或者是資源的方式。
- 編程語言中的繼承:一個類(對象)獲得另外一個類(對象)的屬性和方法的一種方式。
- 面向?qū)ο蟮恼Z言特征:類(C++)C(沒有類)
- js中沒有類(class),支持面向?qū)ο蟮恼Z言。
- 多態(tài)
- 表現(xiàn):
對于相同的操作,不同的對象表現(xiàn)出不同的行為。
隱藏不同。
- 實現(xiàn):
js天生具備多態(tài)的特性(弱類型的語言)
創(chuàng)建對象的四種方法
- 字面量的方式
var book1 = {
name:"悟空傳",
author:"今何在",
press:"湖南文藝出版社",
price:"28.00",
logDes:function(){
console.log("書名:" + this.name + "作者:" + this.author);
}
}
var book2 = {
name:"什么是批判",
author:"福柯",
press:"北京大學(xué)出版社",
price:"52.00",
logDes:function(){
console.log("書名:" + this.name + "作者:" + this.author);
}
}
var book3 = {
name:"數(shù)據(jù)結(jié)構(gòu)",
author:"嚴(yán)蔚敏",
press:"清華大學(xué)出版社",
price:"30.00",
logDes:function(){
console.log("書名:" + this.name + "作者:" + this.author);
}
}
console.log(book1.name);
boo1.logDes();
就用洗衣服來形象的打個比方
如果你是用手洗的話,那就不得不考慮 倒水-搓衣服-加洗衣液-清水涮-手?jǐn)Q干-晾起來 這就是面向過程
但如果你忽略這些步驟 直接放洗衣機(jī)洗的話 可能都不用考慮晾干的步驟 這就是面向?qū)ο?/p>
var zhangsan = {
name:"張三",
sex:"男",
age:18,
address:"天上人間1號公館",
eat:function () {
console.log('能吃');
},
sleep:function () {
console.log("能睡");
},
say:function () {
console.log("能說話");
},
run:function () {
console.log("能運動");
},
song:function () {
console.log("能唱歌");
}
};
//打印對象的屬性并調(diào)用相關(guān)的方法
console.log(zhangsan.name,zhangsan.age,zhangsan.address);
zhangsan.say();
zhangsan.sleep();
高內(nèi)聚和低耦合(電路)
冗余(重復(fù)的東西)-->封裝(提取相同的部分作為函數(shù)體,抽取不同的部分作為參數(shù))
- 封裝
作用:方便代碼的維護(hù),提高代碼的復(fù)用性,更安全的訪問數(shù)據(jù)的方式
注意: js中的封裝多了一層意思,就是使用對象來封裝變量和函數(shù) - 繼承
- 現(xiàn)實生活中的繼承:繼承遺產(chǎn),一個人獲得另一個人所擁有的財富或者是資源的方式。
- 編程語言中的繼承:一個類(對象)獲得另外一個類(對象)的屬性和方法的一種方式。
- 面向?qū)ο蟮恼Z言特征:類(C++)C(沒有類)
- js中沒有類(class),支持面向?qū)ο蟮恼Z言。
- 多態(tài)
- 表現(xiàn):
對于相同的操作,不同的對象表現(xiàn)出不同的行為。
隱藏不同。 - 實現(xiàn):
js天生具備多態(tài)的特性(弱類型的語言)
- 表現(xiàn):
創(chuàng)建對象的四種方法
- 字面量的方式
var book1 = {
name:"悟空傳",
author:"今何在",
press:"湖南文藝出版社",
price:"28.00",
logDes:function(){
console.log("書名:" + this.name + "作者:" + this.author);
}
}
var book2 = {
name:"什么是批判",
author:"福柯",
press:"北京大學(xué)出版社",
price:"52.00",
logDes:function(){
console.log("書名:" + this.name + "作者:" + this.author);
}
}
var book3 = {
name:"數(shù)據(jù)結(jié)構(gòu)",
author:"嚴(yán)蔚敏",
press:"清華大學(xué)出版社",
price:"30.00",
logDes:function(){
console.log("書名:" + this.name + "作者:" + this.author);
}
}
console.log(book1.name);
boo1.logDes();
存在的問題:
創(chuàng)建的對象無法復(fù)用,復(fù)用性差
如果需要創(chuàng)建多個相似的對象,那么代碼中冗余度太高(重復(fù)的代碼太多)
- 內(nèi)置的構(gòu)造函數(shù)
//01 創(chuàng)建空的對象
var book1 = new Object();
//02 設(shè)置屬性
book1.name = "花田半畝";
book1.author = "田維";
book1.price = "40.01";
//03 設(shè)置方法
book1.logDes = function (){
console.log("書名:" + this.name);
}
book1.logDes();
//創(chuàng)建多個對象
var book2 = new Object();
book2.name = "三國演義";
book2.author = "羅貫中";
book2.price = "34.01";
book2.logDes = function (){
console.log("書名:" + this.name);
}
console.log(book1);
console.log(book2);
存在的問題:
創(chuàng)建的對象無法復(fù)用,復(fù)用性差
如果需要創(chuàng)建多個相似的對象,那么代碼中冗余度太高(重復(fù)的代碼太多)
- 簡單工廠函數(shù)創(chuàng)建對象
//01 封裝創(chuàng)建對象的過程
function createBook () {
var book = new Object();
book.name = "聲名狼藉者的生活";
book.price = 42.00;
book.author = "福柯";
book.press = "北京大學(xué)出版社";
book.read = function () {
console.log("我的書名為:聲名狼藉者的的生活,作者為福柯....");
};
return book;
}
//02 使用封裝好的工廠函數(shù)來創(chuàng)建對象
var book1 = createBook();
var book2 = createBook();
//03 打印對象的屬性并調(diào)用對象的方法
console.log(book1.name);
console.log(book2.name);
book1.read();
book2.read();
console.log("_________________________");
//04 說明:以上代碼確實能夠快速簡單的創(chuàng)建出新的對象,但是創(chuàng)建出來的對象內(nèi)部的屬性和方法相同,這并不是我們想要的。
//05 對上面的工廠函數(shù)進(jìn)行改進(jìn)
//改進(jìn)思路:封裝不變的部分,提取變化的部分作為參數(shù)
function createBookNew (name,price,author,press) {
var book = new Object();
book.name = name;
book.price = price;
book.author = author;
book.press = press;
book.read = function () {
console.log("我的書名為:"+book.name+",作者為"+book.author+"....");
};
return book;
}
//06 使用新的工廠函數(shù)來創(chuàng)建對象
var book1 = createBookNew("聲名狼藉者的的生活","42.00","福柯","北京大學(xué)出版社");
var book2 = createBookNew("人性的枷鎖","49.00","毛姆","華東師范大學(xué)出版社");
var book3 = createBookNew("悟空傳","28.00","今何在","湖南文藝出版社");
//07 打印對象的屬性,調(diào)用對象的方法
console.log(book1.name);
console.log(book2.name);
console.log(book3.name);
book1.read();
book2.read();
book3.read();
存在的問題:
如果創(chuàng)建多個不同類型的對象,那么我們無法分辨
-
自定義構(gòu)造函數(shù)創(chuàng)建對象
- 提供一個構(gòu)造函數(shù)
- 通過this指針來設(shè)置屬性和方法
- 通過new操作符創(chuàng)建對象
//1.提供一個構(gòu)造函數(shù)
//構(gòu)造函數(shù)簡單介紹:
//作用:對對象進(jìn)行一些初始化的設(shè)置
//和普通函數(shù)區(qū)別:(01)首字母大寫(02)調(diào)用方式不一樣和new配合使用
function Person(name,age){
// 默認(rèn) 創(chuàng)建對象
//var o = new Object();
//默認(rèn)會賦值給this
//this = o;
//2. 通過this指針來設(shè)置屬性和方法
this.name = name;
this.age = age;
this.showName = function(){
console.log(this.name);
};
this.showAge = function(){
console.log(this.age);
}
//默認(rèn)返回
//return this;
}
//3. 使用new操作符來創(chuàng)建對象
var p1 = new Person("張三",20);
var p2 = new Person("張老漢",200);
console.log(p1);
console.log(p2);
/*
1. 自定義構(gòu)造函數(shù)方式創(chuàng)建對象內(nèi)部的實現(xiàn)細(xì)節(jié)
1.1 我們在使用new關(guān)鍵字調(diào)用構(gòu)造哈函數(shù)的時候,內(nèi)部默認(rèn)會創(chuàng)建一個空的對象
1.2 默認(rèn)會把這個空的對象賦值給this
1.3 通過this來設(shè)置新對象的屬性和方法
1.4 在構(gòu)造函數(shù)的最后,默認(rèn)會把新創(chuàng)建的對象返回
2.自定義構(gòu)造函數(shù)和工廠函數(shù)對比
2.1 函數(shù)的名稱不一樣,構(gòu)造函數(shù)首字母大寫
2.2 自定義構(gòu)造函數(shù)創(chuàng)建方式內(nèi)部會自動的創(chuàng)建空對象并且賦值給this
2.3 默認(rèn)會自動返回新創(chuàng)建的對象
3.返回值
3.1. 沒有顯示的return ,默認(rèn)會把新創(chuàng)建的對象返回
3.2. 顯示的執(zhí)行了return語句,就得看具體的情況
3.2.1 返回的是值類型,那么直接忽略該返回,把新創(chuàng)建的對象返回
3.2.2 返回的是引用類型的數(shù)據(jù),會覆蓋掉新創(chuàng)建的對象,直接返回引用數(shù)據(jù)類型的值
*/
function Dog(name)
{
this.name = name;
//return "demo"; 忽略
//return function (){};
}
var dog = new Dog("阿黃");
console.log(dog);
構(gòu)造函數(shù)的的注意事項
- 函數(shù)傳值
function Student(number,className,log){
this.number = number;
this.className = className;
this.log = log;
}
var stu1 = new Student("201601","九陰真經(jīng)修煉01班",function(){
console.log("學(xué)號:" + this.number);
});
var stu2 = new Student("201602","九陰真經(jīng)修煉01班",function(){
console.log("班級名稱:" + this.className);
});
stu1.log();
stu2.log();
- 對象的類型(判斷)
function Person(){};
function Dog(){};
var p1 = new Person();
var dog1 = new Dog();
//關(guān)鍵字 instanceOf 用來判斷當(dāng)前對象是否是某個類型的實例(檢查某個對象是否是使用指定構(gòu)造函數(shù)創(chuàng)建的)
//語法: 對象 instanceOf 構(gòu)造函數(shù)(類型)
console.log(p1 instanceof Person);
console.log(p1 instanceof Dog);
console.log(dog1 instanceof Person);
console.log(dog1 instanceof Dog);
- 構(gòu)造器屬性(獲取
function Person(){};
function Dog(){};
var p1 = new Person();
var dog1 = new Dog();
//在所有的對象中,都擁有一個構(gòu)造器屬性:constructor
console.log(p1.constructor);
console.log(dog1.constructor);
-
函數(shù)調(diào)用
new :創(chuàng)建對象,并在最后返回該對象
構(gòu)造函數(shù):用于初始化對象
以普通函數(shù)的方式來調(diào)用構(gòu)造函數(shù),那么內(nèi)部的this指向的是window
function Person(name)
{
if(this instanceof Person)
{
this.name = name;
}else
{
return new Person(name);
}
}
var p1 = new Person("嗶哩嗶哩");
//構(gòu)造函數(shù)本身是一個函數(shù),在調(diào)用可以直接調(diào)用
var p2 = Person("嘩啦嘩啦"); //這是一個錯誤的演示(不要這樣寫代碼)
console.log(p2); //undefined
-
存在問題
** 把函數(shù)寫在外部,破壞了封裝性。
增加一個全局變量。**
var showName = function(){
console.log("姓名:");
}
function Person(name,age){
this.name = name;
this.age = age;
this.showName = showName;
}
//創(chuàng)建對象
var p1 = new Person("張小花",18);
var p2 = new Person("張全蛋",99);
p1.showName();
p2.showName();
//每創(chuàng)建一個對象,內(nèi)部都會聲明一個showName函數(shù)
console.log(p1.showName == p2.showName); //false