第一章:面向?qū)ο蟮腏avaScript
面向?qū)ο蟮某绦蛟O計
面向?qū)ο蟪绦蛟O計(oop)中最常用到的概念:
- 對象、方法、屬性
- 類
- 封裝
- 聚合
- 重用與繼承
- 多態(tài)
封裝通常有兩部分組成。
- 相關(guān)的數(shù)據(jù)(用于存儲數(shù)據(jù))
- 基于這些數(shù)據(jù)所能做的事情(多能調(diào)用的方法)
通過繼承可以實現(xiàn)代碼的復用。
第二章:基本數(shù)據(jù)類型、數(shù)組、循環(huán)及條件表達式
基本數(shù)據(jù)類型
- 數(shù)字 ——包括浮點數(shù)與整數(shù),列如這些屬于數(shù)字,1、100、3.14;
- 字符竄 ——包括由任意數(shù)量字符組成的序列,例如:“a”、“one”、“one 2 three”;
- 布爾值 ——包括true和false;
- undefined ——不存在的變量,或者聲明未初始化的變量,值只有一個:undefined;
- null ——通常指沒有或者是空值。
JavaScript數(shù)據(jù)類型主要分為兩個部分:
- 基本數(shù)據(jù)類型;
- 非基本類型(即對象)
任何不屬于基本數(shù)據(jù)類型的東西都屬于對象。
可以使用查看類型操作符——typeof 查看某個變量或者值的類型是什么。
數(shù)組
數(shù)組是一種數(shù)據(jù)存儲的形式,數(shù)組的聲明:
var a=[];
var a=[1,2,3];
數(shù)組的索引下標是從0開始的,并且按照每一個元素的位置依次遞增
可通過方括號中的索引值訪問數(shù)組元素,可存儲任何類型的數(shù)據(jù),包括另一個數(shù)組。
條件與循環(huán)表達式
- if條件表達式
- switch語句
- while、do-while、for,及for-in循環(huán)
第三章:函數(shù)
什么是函數(shù)
function sum(a, b) {
var c=a+b;
return c;
}
一般來說,函數(shù)聲明通常是由下面幾部分組成的:
1.關(guān)鍵詞function;
2.函數(shù)名稱,這里即sum;
3.函數(shù)需要的參數(shù);
4.函數(shù)所要執(zhí)行的代碼塊,稱為函數(shù)體;
5.return 子句。函數(shù)通常有返回值,且只有一個,如要返回多個,可以可考慮放進一個數(shù)組。
arguments:函數(shù)內(nèi)建變量,接收的所有參數(shù),結(jié)構(gòu)類似數(shù)組,可通過索引進行運用。
預定義函數(shù)
- parseInt(); // 接收任何輸入值轉(zhuǎn)換為整數(shù)型輸出 ,記得定義第二個參數(shù)確定輸出的是什么進制的數(shù)值,默認是十進制,例如,從日歷中讀日期,對于08這樣的數(shù)值,如果不定義,會出現(xiàn)意想不到的結(jié)果。
- paseFlat( ); // 功能和parseInt( )差不多,它只支持將輸入值轉(zhuǎn)為十進制,因此該函數(shù)只有一個參數(shù);可接受指數(shù)形式的數(shù)據(jù),這一點和parseInt()不同。
- isNaN( );
- isFinite( );
- encodeURI( );
- decodeURI( );
- ...
函數(shù)的作用域
沒有塊作用域,只有函數(shù)作用域,“全局變量”指的是所有函數(shù)外的變量,與之對應的“局部變量”是指在某個函數(shù)中定義的變量。函數(shù)內(nèi)的代碼可以訪問全局變量,反之不行。
var a=3;
function text(){
alert(a);
var a=5;
alert(a);
}
text();
上面的例子,第一個alert 結(jié)果是undefined,第二個則為5;
函數(shù)也是數(shù)據(jù)
在JavaScript中,函數(shù)也是數(shù)據(jù),也就是說我們可以把函數(shù)賦值給一個變量,
var f=function(){
return 1;
}
上面的這種定義方式也稱為函數(shù)標識法。
function(){return 1} 是一種函數(shù)表達式,其可以被命名,稱為命名函數(shù)表達式,所以以下是合法的,
var f = function myFunc(){
return 1;
}
函數(shù)聲明和函數(shù)命名函數(shù)表達式的差別表現(xiàn)在于他們的上下文,函數(shù)聲明只出現(xiàn)在程序代碼里(在另一個函數(shù)體中,或者在主程序中)
匿名函數(shù)和回調(diào)函數(shù)
var f=function(a){
return a;
}
匿名函數(shù)即沒有名字的函數(shù),特別是它不被賦值給變量,單獨使用的時候,通過匿名函數(shù)可以做些什么呢:
- 可將匿名函數(shù)作為參數(shù)傳給其他函數(shù),,這樣,接收函數(shù)就能利用我們傳遞的函數(shù)來完成某些事
- 可以定義某些匿名函數(shù)進行某些一次性的任務
function byTwo(a,b,c,callback){
var arr=[];
for(var i=0;i<3;i++){
arr[i]=callback(arguments[i]*2);
}
return arr;
}
byTwo(1,2,3,function(a){ return a+1 }) // 輸出 [3,5,7]
以上例子為匿名函數(shù)在回調(diào)函數(shù)中的用處,
(function(){
alert('box');
})()
匿名函數(shù)在即時(自調(diào))函數(shù)中作用,其最大的好處是不會產(chǎn)生任何的全局變量,其無法重復執(zhí)行,所以適合執(zhí)行一些一次性的或初始化的任務。
閉包
討論閉包需要了解作用域的概念,
我們知道,JavaScript不存在大括號級的作用域,但它有函數(shù)作用域,也就是說函數(shù)內(nèi)定義的所有變量在該函數(shù)外是不可見的,而在函數(shù)內(nèi)可以訪問的變量既來自它自身的作用域,可以來自其“父級”作用域,這樣就形成了一條作用域鏈,該鏈的長度(深度)取決于我們的需要。
閉包#1
var a="global variable";
var F=function(){
var b="local variable";
var N=function(){
var c="inner local"
return b;
};
return N;
}
console.log(b) // undefined
var inner= F();
inner(); // local variable
函數(shù)F中包含局部變量b,因此后者在全局空間里是看不到的,N有自己的私有空間,但同時可以訪問F()的空間和全局空間,所以b對于來它是可見得。因為F()是可以在全局空間被調(diào)用的,所以我們將它的返回值賦于另一個全局變量,從而生成可以訪問F()私有空間的全局函數(shù)。
閉包#2
function F(){
var arr=[],
for(var i=0;i<3;i++){
arr[i]=function(){
return i;
}
}
return arr;
}
F() // 輸出 [3,3,3];
function F(){
var arr=[],
for(var i=0;i<3;i++){
arr[i]=(function(x){
return x;
})(i)
}
return arr;
}
F() // 輸出 [3,3,3];
第四章:對象
這一章主要講的是:
- 如何創(chuàng)建并使用對象;
- 什么是構(gòu)造器對象;
- JavaScript中的內(nèi)置對象及運用;
事實上對象和數(shù)組的情況很相似,不同的是鍵值類型是自定義的,索引方式不再是數(shù)字,而是一些更友好的鍵名。
var hero={
breed: 'Turtle',
occupation: 'Ninja'
}
正如所見:
- 一個用于表示該對象名的hero;
- 與定義數(shù)組時所用的中括號[ ]不同的是使用{ };
- 中括號分割開的是組成該對象的元素(通常稱為屬性);
- 鍵/值之間使用冒號隔開
對象的屬性可以有函數(shù),稱之方法,
var hero={
breed: 'Turtle',
occupation: 'Ninja',
getbreed: function(){
return this.breed;
}
}
// 可通過兩種方式訪問對象的屬性
hero.breed; // 方式一
hero['breed']; // 方式二
// 調(diào)用對象的方法和其他函數(shù)的方式相同,在指定的函數(shù)名后面加一對括號即可:
hero.getbreed() ;
hero['getbreed']();
構(gòu)造器函數(shù)
我們可以通過構(gòu)造器函數(shù)的方式來創(chuàng)建對象,
function Hero(){
this.occupation='Ninja';
}
var hero=new Hero();
hero.occupation // 'Ninja'
使用構(gòu)造器創(chuàng)建對象,可以進行傳參,可以利用同一個構(gòu)造器創(chuàng)建不同的對象。
構(gòu)造器屬性
當創(chuàng)建對象時,同時也賦予該 對象一個特殊的屬性---即構(gòu)造函數(shù)屬性(constructor property) ,該屬性實際上是一個指向用于創(chuàng)建該對象的構(gòu)造器函數(shù)的引用。
hero.constructor // "function Hero(){ this.occupation='Ninja';}"
typeof(hero.constructor) // "function"
instanceof操作符
通過instanceof操作符可以測試一個對象是不是由某個構(gòu)造器函數(shù)所創(chuàng)建的。
hero.instanceof.Hero // true
返回對象的函數(shù)
不使用new操作符調(diào)用構(gòu)造函數(shù)創(chuàng)建對象以外,拋開new操作符,只用一般的函數(shù)來創(chuàng)建對象。
function factory(name){
return {
name:name
}
}
var o = faactory('jay');
o.name // 'jay'
傳遞對象和比較對象
對象的拷貝和傳遞,都是對象的引用,在引用上所做的任何改動,實際上都會影響它所引用的原對象。
var a = { num: 1 };
var b = a;
b.num; // 1
b.num = 2;
a.num; // 2
var a = { num: 1 };
var b = { num: 1 };
a === b; // fasle
a == b; // fasle
var c = a;
c === a; // true
內(nèi)建對象
- Object
- Array
- Function
- Boolean
- Number
第五章:原型
本章涉及的話題
- 介紹每個函數(shù)都擁有的prototype屬性,而該屬性所存儲的就是原型對象
- 如何為原型對象添加屬性
- 如何使用原型對象中的新增屬性
- proto介紹,該屬性用于保存各對象原型的神秘鏈接
- 原型方法介紹,包括isProtottypeOf()、hasOwnProprety()、propertyIsEnumerable()等
function foo(a,b){
return a*b;
}
foo.length; // 2
foo.constructor; // function foo(a,b){ return a*b; }
typeof foo.prototype; // object
foo.prototype={ }; // 可以向添加屬性和方法,對 foo不會有影響,當foo為構(gòu)造函數(shù)時,其才會起作用
對于原型來說,最重要的一點是理解它的‘實時性’,在JavaScript中,幾乎所有的對象都是靠傳遞引用的方式來進行傳遞的,所以我們所創(chuàng)建的每一個對象實例并沒有屬于自己的原型副本,可隨時修改prototype屬性,由同一構(gòu)造器所創(chuàng)建的所有對象的prototype屬性也會一起改變。
自身屬性和原型屬性
當我們訪問對象實例的某個屬性時,JavaScript會遍歷所有該對象所有屬性,如果找到該屬性后立即返回,如果沒有找到,腳本引擎會繼續(xù)去查詢用于創(chuàng)建當前對象的構(gòu)造器的原型。如果在原型中找到該實例會立即使用該屬性。
function Hero(){
this.name = 'java';
this.sex = 'man'
}
Hero.prototype.info='it';
Hero.prototype.sex ='woman';
var hero = new Hero();
hero.name ; // 'java'
hero.info ; // 'it'
hero.sex; // 'man'
hero.hasOwnProperty('sex') // true;
hero.hasOwnProperty('info') // false;
當自身屬性和原型屬性同名時,自身的屬性優(yōu)先級高于原型屬性,使用
hasOwnProperty方法可以判斷一個對象的屬性時自身屬性還是原型屬性。
枚舉屬性
for適合使用在數(shù)組上,for-in更適合對象,如果想獲得某個對象的所有屬性的類列表,可以使用for-in。
var params={
productid: 666,
section: 'products'
}
var url = 'https://example.org/page.php?',
i,
quert = [];
for( i in params){
quert.push(i + '=' + params[i]);
}
url += quert.join('&') // url = 'https://example.org/page.php?productid=666§ion=products',
需要注意的細節(jié):
- 并不是所有的屬性 for- in 循環(huán)都可以顯示的,例如(數(shù)組) length、construction 屬性就不會被顯示,那些會顯示的屬性稱為可枚舉的,可通過propertyIsEnumerable方法來判斷對象的某個屬性是否可枚舉。
- 原型鏈中的各個原型屬性也會被顯示出來,當然前提是他們是可枚舉的。
- 對于所有的原型屬性, propertyIsEnumerable 都會返回false
function Fadget(name,color){
this.name = name;
this.color = color;
this.getName = function(){
return this.name;
}
}
Fadget.prototype.price = 10;
Fadget.prototype.rating = 3;
var newtoy = new Fadget('webcam','black');
for( var prop in newtoy){
console.log(prop + '=' + newtoy[prop ])
}
// name = name
// name = name
// getName = function(){
return this.name;
}
// price = 10
// rating = 3
// 使用hasOwnProperty對對象屬性和原型屬性做一個區(qū)分
newtoy .hasOwnProperty('name '); // true
newtoy .hasOwnProperty('price '); // false
for(var porp in newtoy ){
if(newtoy.hasOwnProperty(porp)) {
console.log(porp + '=' +newtoy[porp] );
}
}
// name = name
// name = name
// getName = function(){
return this.name;
}
//propertyIsEnumerable,該方法會對所有的非內(nèi)建對象屬性返回true
//而對于內(nèi)建對象和方法來說,大部分都是不可枚舉的,
newtoy.propertyIsEnumerable('name ') // true
newtoy.propertyIsEnumerable('constructor ') // false
//任何原型鏈上的屬性也是不可枚舉的
newtoy.propertyIsEnumerable('price ') // false
// 但需要注意,如果propertyIsEnumerable()調(diào)用的是來自原型鏈上的某個對象,那么該對象中的屬性也是枚舉的
newtoy.constructor .prototype.propertyIsEnumerable('price ') // true
每個對象中都有isPrototypeOf()方法,這個方法會告訴我們當前對象是否是另一個對象的原型。
proto IE 之類平臺不存在,所以使用上存在不能夸平臺,還有和prototype 并不等價的,它屬于某個對象實例的屬性,而后者是屬于構(gòu)造函數(shù)的。