1.1 js 面向對象的基本概念和基本使用方法
js 面向對象的基本概念和基本使用方法
- -> js 是不是一個面向對象的語言?
- 說不是:因為與傳統面向對象的理論語言有矛盾。C#,Java。
- 說是:因為js裏面到處都是對象,數組,時間,正則… 和 DOM。也可以像傳統面向對象的語言那樣用 new 的方式創建對象
- -> 其實js是一個基於對象的多範式編程語言。
- 面向過程的方式
- 面向對象的方式
- 函數式 遞歸與鏈式 例: Jquery 鏈式編程
面向對象的概念
對象的定義:無序屬性的集合,其屬性可以包含基本值,對象或是函數
1. 面向:將臉朝向… -> 關註,用
2. 面向過程 -> 使用過程的方式開發
關註過程,步驟,細節,順序。 就是自己動手豐衣足食
3. 面向對象開發 -> 使用對象的方式開發
要做什麽,找到對象,告訴他做,等結果
4. 面向對象不是面向過程的替代,是面向過程的封裝,可以理解為面向對象編程就是面向編程的一種簡化
萬物皆對象
-
在實際開發中,對象是一個抽象的概念,可以簡單理解為: 數據集或功能集。可以混合使用
- 數據集: 很多數據打包到一起。 { name: ‘張三’, age:19, gender:’男’ }
- 假設展示 10 個商品數據,每個商品有名字,描述,價格,圖片等
- 對象可以用來保存數據,每一個商品可以變成對象 { name: ‘123’, desc:’123’, price: 0 }
- 引入數組,將多個對象數據存儲在數組中(數組也是對象)
- 功能集(函數集,方法集)
- 在 js 中,所謂的對象就是 鍵值對 的集合
- 數據集: 很多數據打包到一起。 { name: ‘張三’, age:19, gender:’男’ }
-
給頁面中所有的div和p添加邊框,設置寬高
<body>
<!-- 給頁面中所有的div和p添加邊框,設置寬高 -->
<div>div1</div>
<p>p標簽</p>
<div>div2</div>
</body>
<script>
/* 獲得所有div */
var divs = document.getElementsByTagName(‘div‘);
var ps = document.getElementsByTagName(‘p‘);
/* 設置樣式 */
/* 由於 getby 獲取的是 偽數組 */
for ( var i = 0; i < divs.length; i++ ) {
divs[ i ].style.border = ‘1px solid red‘;
divs[ i ].style.width = ‘300px‘;
divs[ i ].style.height = ‘200px‘;
}
for ( var i = 0; i < ps.length; i++ ) {
ps[ i ].style.border = ‘1px solid blue‘;
ps[ i ].style.width = ‘300px‘;
ps[ i ].style.height = ‘200px‘;
}
</script>
- 利用函數封裝較長的功能
<script>
/* 利用函數封裝較長的功能 */
function tag ( tagName ) {
return document.getElementsByTagName( tagName );
}
var divs = tag(‘div‘);
var ps = tag(‘p‘);
for ( var i = 0; i < divs.length; i++ ) {
divs[i].style.border = ‘1px solid red‘;
divs[i].style.width = ‘300px‘;
divs[i].style.height = ‘200px‘;
}
for ( var i = 0; i < ps.length; i++ ) {
ps[i].style.border = ‘1px solid blue‘;
ps[i].style.width = ‘300px‘;
ps[i].style.height = ‘200px‘;
}
<script>
- 封裝函數進行循環
<script>
function tag ( tagName ) {
return document.getElementsByTagName( tagName );
}
function addCss( array, border, width, height ) {
for( var i = 0; i < array.length; i++ ) {
array[i].style.border = border;
array[i].style.width = width;
array[i].style.height = height;
}
}
var divs = tag( ‘div‘ );
var ps = tag(‘p‘);
addCss( divs, ‘1px solid red‘, ‘400px‘, ‘50px‘ );
addCss( ps, ‘1px solid blue‘, ‘300px‘, ‘50px‘ );
</script>
- addCss的改良
<script>
function tag ( tagName ) {
return document.getElementsByTagName( tagName );
}
function addCss( array, styles ) {
for( var i = 0; i < array.length; i++ ) {
for( var k in styles ) {
array[i].style[k] = styles[k];
}
}
}
var divs = tag(‘div‘);
var ps = tag(‘p‘);
addCss( divs, {
‘border‘: ‘1px solid red‘,
‘width‘: ‘400px‘,
‘height‘: ‘50px‘
});
addCss( ps, {
‘border‘: ‘1px solid red‘,
‘width‘: ‘400px‘,
‘height‘: ‘50px‘
});
</script>
- 自己定義的函數越多,那麽開發的時候就越方便,但是,也有隱患,自己定義的越多,那麽與引入的框架出現沖突的幾率就越大,一旦出現名字沖突了,就會造成框架中的功能無法使用。
- 怎麽辦? 定義的名字越多,問題的幾率越大,最簡單的方法就是盡可能少定義名字
- 定義一個對象,然後所有的函數,變成這個對象的方法即可
<script>
var jespon = {
tag: function( tagName ) {
return document.getElementsByTagName( tagName );
},
addCss: function( array, styles ) {
for( var i = 0; i < array.length; i++ ) {
for( var k in styles ) {
array[i].style[k] = styles[k];
}
}
}
}
var divs = jespon.tag(‘div‘);
var ps = jespon.tag(‘p‘);
jespon.addCss( divs, {
‘border‘: ‘1px solid red‘,
‘width‘: ‘400px‘,
‘height‘: ‘50px‘,
‘background‘: ‘green‘
});
jespon.addCss( ps, {
‘border‘: ‘1px solid red‘,
‘width‘: ‘400px‘,
‘height‘: ‘50px‘
});
</script>
面向對象的特性
- 抽象性:抽取我們所需要的數據信息等
- 封裝性
- 繼承性
- (多態性)
名詞提煉法找對象
- 做一個表格排序
- 面向過程: 1創建表格, 2添加點擊事件, 3排序,更新數據
- 面向對象: 1創建表格對象, 2添加數據
實際開發的時候如果需要完成一個功能
- 首先考慮系統是否提供了對象
- 例如: 創建圖片: var img = new Image(); img.src = ‘…png’;
- 例如: 獲取頁面元素:document
- 用 document對象 獲取導航欄裏面的所有li 標簽
var nav = document.getElementById( ‘nav’ );
var lis = document.getElementsByTagName( ‘li’ );
- 如果系統沒有提供,可以自己定義,或第三方
<script>
var jespon = {
tag: function( tagName ) {
return document.getElementsByTagName( tagName );
},
addCss: function( array, styles ) {
for( var i = 0; i < array.length; i++ ) {
for( var k in styles ) {
array[i].style[k] = styles[k];
}
}
}
attr: ...,
getId: ...
}
<script>
js 的數據類型
- 基本數據類型(值類型):數字 number,字符串 string,布爾 boolean
- 基本數據類型的存儲模型就是一個方格裏面放一個數據
- 復合數據類型(引用類型):對象(數組,時間類型,函數類型)
- 復合類型,除了函數其他的數據類型 無法使用 typeof 來獲得數據類型名,typeof arr 等 拿到的都是object
- 需要使用 Object.prototype.toString.apply( )
- 空類型: null undefined
var arr = [1, 2, 3];
console.log( typeof arr ); //object
console.log( Object.prototype.toString.apply(arr) ); // [object Array]
復合類型的存儲模型
- 復合類型的對象是一個單獨的內存區域, 對象有什麽屬性, 那麽內存區域中就有什麽數據.
變量 p 只存儲該對象的 ‘地址’. 所以 p 不是真正存儲數據的區域.
// 聯想內存邏輯圖
var arr1 = [ 1, 2, 3, 4 ];
var arr2 = [
{ name: ‘張三‘, age: 19, gender: ‘男‘ },
{ name: ‘李四‘, age: 18, gender: ‘男‘ },
{ name: ‘小李‘, age: 17, gender: ‘女‘ }
];
值類型和引用類型的存儲特征
- 值類型的數據,只需要開辟一段內存存儲數據即可
var a = 123;
var b = ‘abc‘;
var c = true;
- 對象類型(引用類型),對象才是真正的數據,需要占據單獨的內存。而變量名只是存儲著對象的內存地址(引用)
- 即創建一個對象,並賦值,需要兩塊內存空間,一個存儲數據(對象)。另一個存儲變量以引用對象
- var o = { name: “張三”, age: 19 },前後各占一塊空間,前者於棧,後者於堆
值類型與引用類型的賦值與傳參的特性
-
賦值:將原變量中的數據拷貝一份,然後存儲到給定變量中
-
值類型
var a = 123; // 有個盒子a,裏面存了123 var b ; // 有個盒子 b, 裏面什麽都沒有 (undenfied) b = a; // 將 a 中存儲的東西賦值一份,然後賦值為 b,即存儲在 b 中
-
- b 和 a 是兩個獨立的變量, 兩者之間不再有關系。
- 改變其中一個數據,另一個不變。
-
引用類型
var o1 = { num:123 }; var o2; // 賦值 o2 = o1; //o1 中存儲的是引用,或‘地址’
- 將 o1 中存儲的內容拷貝一份,存儲到 o2 中,o1 和 o2 雖然是不相同的兩個變量, 即兩個獨立的盒子. 但是由於拷貝的內容是地址,存儲的地址相同。
- 在訪問數據的時候, o1 與 o2 也是訪問同一個數據, o1 將數據修改了, o2 再讀取,讀取的就是修改後的數據。
-
函數參數傳遞
-
什麽是函數參數傳遞
函數要調用,一般會給函數傳遞參數
在調用函數的時候,會將參數中表示的數據拷貝一份,然後給參數賦值 -
值類型傳遞
function foo ( num ) {
console.log( ‘num:‘ + num ); // 123
num++;
console.log( ‘num:‘ + num ); // 124
}
// 調用
var a = 123;
console.log( a ); // 123
foo( a ); // 調用就是執行,將 a 中存的值,拷貝一份
// 然後進入 函數 foo
// 給參數賦值,相當於 num = a;
// 進入函數體,開始執行函數
console.log( a ); // 123
- 引用類型傳遞
function foo ( num ) {
console.log( ‘nu====m:‘ + num[ 0 ] ); // 123
num[ 0 ]++;
console.log( ‘num:‘ + num[ 0 ] ); // 124
}
// 調用
var a = [ 123 ];
console.log( a[ 0 ] ); // 123
foo( a );
console.log( a[ 0 ] ); // 124
此時的賦值特性與前面介紹的值類型引用類型的賦值是一個特點
深拷貝與淺拷貝
什麽是拷貝: 就是創建一個與目標數據一模一樣的數據
var p = { name: ‘張三‘ };
var p1 = p; // 是否存在拷貝
// 一般描述拷貝是指拷貝對象
p1 = {};
p1.name = p.name;// 才是拷貝
給 對象 p 提供一個 clone 方法, 完成拷貝
- 淺拷貝:如果對象的屬性也是一個引用類型, 拷貝的時候不重新創建一個新的對象來實現該屬性的拷貝, 那麽就是淺拷貝.即任何不完全的拷貝都是淺拷貝
- 深拷貝:將兩個對象完全從內存中隔離開, 就是深拷貝. 即每一個引用屬性, 以及引用屬性的引用屬性, … 全部拷貝出來.
構造函數( 構造器 constructor )的作用
js 中對象的動態特性, 即 想要什麽屬性就可以給什麽屬性
var o = {}; // 這時 o 對象沒有 name 屬性
o.name = "aaa"; // 這時 o 對象擁有了 name 屬性且值為 “aaa”
在 js 中 對象如果沒有指定的屬性, 只需要利用賦值就 可以給對象 動態 提供該屬性.
- 點語法與關聯數組語法
o.name = ‘jim‘; // 點語法賦值
console.log( o.name ); // 點語法取值
o[ ‘name‘ ] = ‘tom‘; // 關聯數組語法賦值
console.log( o[ ‘name‘ ] ); // 關聯數組語法取值
- 創建一個 Person 對象
var p = {}; // 什麽都沒有的對象
// 根據需要添加成員
p.name = ‘張三‘;
p.age = 30;
p.gender = ‘男‘;
- 簡化,提供一個創建 Person 對象的函數
function createPerson( name, age, gender ) {
var p = {};
p.name = name;
p.age = age;
p.gender = gender;
return p;
}
var p1 = createPerson( ‘jepson‘, 19, ‘男‘ );
var p2 = createPerson( ‘lucy‘, 18, ‘女‘ );
這個( 這種類型 )的函數就是用來創建對象的, 即生產對象. 常常將這類函數, 稱為 **‘工廠函數‘**。
構造方法創建對象
構造器中不需要 return 語句. 一般也可以不寫
調用構造器的時候, 使用 new 運算符引導
在構造器中 this 表示當前對象. 給對象提供成員使用 this.xxx 的 方式
- 將 createPerson 改造成構造器
function createPerson( name, age, gender ) {
this.name = name;
this.age = age;
this.gender = gender;
}
// 調用構造器創建對象
var p = new createPerson( ‘jepson‘, 19, ‘男‘ );
- 構造器創建對象的本質: 還是使用對象的動態特性
-> 首先執行 new 運算符. 即創建對象. 可以簡單看做為 {} 的簡寫, var p = new … ‘相當於’ var p = {}
-> 調用構造器. 並隱含一個參數, 即剛剛創建的對象.
-> 在構造器中使用 this 引用剛剛創建出來的對象.
-> 構造器結束是 默認返回 this - 補充說明
-> 構造器的名字, 一般使用 Pascal 命名規則( 首字母大寫的 )
-> 一般為了與其他面向對象的編程語言( C++, C#, Java )保持一致. 稱構造函數名為類名
function Person( name, age, gender ) {
this.name = name;
this.age = age;
this.gender = gender;
}
// 調用構造器創建對象
var p = new Person( ‘jepson‘, 19, ‘男‘ );
異常與捕獲
- 異常:簡單的說, 就是代碼在執行過程中出現的錯誤. 並不是代碼的語法錯誤,一旦出現異常, 其後的代碼, 不再執行。
-
try catch 語法
1) try-catch 形態try { 代碼 } catch ( e ) { 代碼 }
2) try-catch-finally 形態
-
自定義拋出異常
一般可以封裝函數完成特定的功能 -
拋出異常的語法
throw 對象
1.1 js 面向對象的基本概念和基本使用方法