《JavaScript面向對象的編程指南》--讀書筆記

第一章、引言

1.5 面向對象的程序設計經常使用概念

對象(名詞):是指「事物」在程序設計語言中的表現形式。
這裏的事物能夠是任何東西,咱們能夠看到它們具備某些明確特徵,能執行某些動做。
這些對象特徵就叫作屬性(形容詞),動做稱之爲方法(動詞)。javascript

類:實際上就是對象的設計藍圖或製做配方。類更多的是一種模板,而對象就是在這些模版的基礎上被建立出來的。html

封裝:主要闡述對象中包含的內容。一般包括:java

  • 相關數據(用於存儲屬性)
  • 基於這些數據所能作的事(所能調用的方法)

聚合:將幾個現有對象合併成一個新對象的過程
繼承:實現代碼重用
多態:不一樣對象經過相同的方法調用來實現各自行爲的能力
web

第二章、基本數據類型、數組、循環及條件表達式

2.3基本數據類型

2.3.2 指數表示法

2e+3表示在數字2後面加3個0,即2000ajax

typeof Infinity  // number 
typeof NaN       // number
typeof null      // object   null值表示一個空指針對象
2.3.4 惰性求值

Javascript引擎在一個邏輯表達式中遇到一個非布爾類型操做數,
那麼該操做數的值就會成爲該表達式返回的結果。正則表達式

true || "something"  //true
true && "something"  //"something"

2.9 練習題

var s = "1s";  //隱式轉換Number()用於任何數據類型
s++  //NaN
10 % "0"  //NaN   若是被除數是有限大的數值而除數是零,則結果是NaN
//乘法口訣程序代碼
for(var i=1;i<10;i++){
    for(var j=1;j<=i;j++){
        document.write(j+"*"+i+"="+i*j+" ");
    }
    document.write("<br>");
}

第三章、函數

3.1 函數

3.1.2 函數參數

函數內部都有一個內建的arguments數組,能返回函數所接收的全部參數編程

function sumOnSteroids(){
    var i,res = 0;
    for(i = 0; i < arguments.length; i++){
        res += arguments[i];
    }
    return res;
}
sumOnSteroids(1,2,3,4,5,6); //21

3.3 函數的做用域

var a = 123;
function f(){
    alert(a);   //undefined  這是由於函數域優先於全局域
    var a = 1;
    alert(a);  //1
}
f();
3.4.2 回調函數

當咱們將函數B傳遞給函數A,並由A來執行B時,B就成了一個回調函數json

function A(a,b,c,callback){
    var i=0,ar = [];
    for(i=0;i<3;i++){
        ar[i] = callback(arguments[i]*2);
    }
    return ar;
}
function B(a){  //回調函數
    return a+1;
}
A(a,b,c,B)
3.4.4 自調函數
(function(name){
    alert('Hello '+name+' !');
})('Jesse')  //Hello Jesse !
//第二對括號起到的是當即調用的做用,同時也是向函數傳遞參數的地方

使用自調函數的好處是不會產生任何全局變量,缺點是沒法重複執行,這使得匿名自調函數最合適於執行一些一次性的或者初始化的任務設計模式

3.4.5 私有函數
function a(param){
    function b(theinput){  //私有函數
        return theinput * 2
    };
    return 'The result is '+b(param)
}

使用私有函數的好處:數組

  • 有助於全局命名空間的純淨性(命名衝突的機會很小)
  • 私有性--不被外部其餘用用程序所用
3.4.7 能重寫本身的函數

這對於要執行某些一次性初始化工做的函數很是有用

function a(){
    alert('A');      //第一次調用該函數時該語句會被執行
    a = function(){  //第一次調用時a被賦予新函數
        alert('B');  //第二次調用該函數時該語句會被執行
    };
}
var a = function(){
    function someSetup(){
        var setup = 'done'
    }
    function actualWork(){
        alert('work')
    }
    someSetup();
    return actualWork;
}();

3.5 閉包

3.5.1 做用域鏈

在函數內定義的變量在函數外是不可見的,
可是若是該變量是在某個代碼塊中定義的(if或for語句中),它在代碼塊外是可見的。

3.5.2 詞法做用域

在javascript中每一個函數都有一個屬於本身的詞法做用域,也就是說每一個函數
在被定義時(而非執行時)都會建立一個屬於本身的環境(即做用域)

function f1(){var a = 1;f2();}
function f2(){return a;} //f2()被定義時a是不可見的,只能訪問自身做用域和全局做用域
f1();   //a is not defined
3.5.3 利用閉包突破做用域鏈
3.5.3.1 閉包#1
function f(){
    var b = "m";
    return function(){  //有着私有做用域,能夠訪問f()的做用域和全局做用域
        return b;
    }    
}
var n = f();
n();   //m

f()是全局函數,咱們能夠將它的返回值賦值給另外一個全局變量,
從而生成一個能夠訪問f()私有空間的新全局函數

3.5.3.3 相關定義與閉包#3

若是一個函數在其父函數返回以後想留住對父級做用域的連接,就必需要爲此創建一個閉包

3.5.3.4 循環中的閉包
function f(){
    var a = [];
    for(var i = 0; i < 3; i++){
        a[i] = function(){
            return i;
        }
    }
    return a;
}
var s = f();
s[0](); //3
s[1](); //3
s[2](); //3

咱們在這裏建立了3個閉包,它們都指向一個共同的局部變量i,
可是閉包不會記錄它們的值,他們所擁有的只是一個i的引用,
所以只能返回i的當前值(循環結束時i=3).

function f(){
    var a = [];
    for(var i = 0; i < 3; i++){
        a[i] = (function(x){
            return function(){
                return x;
            }
        })(i);
    }
    return a;
}
var s = f();
s[0](); //0
s[1](); //1
s[2](); //2

3.7 練習題

1.十六進制值轉爲顏色函數getRGB()

function getRGB(hex){
    var rgb=[0,0,0];
    if(/#(..)(..)(..)/g.test(hex)){
        rgb=[parseInt(RegExp.$1,16),parseInt(RegExp.$2,16),parseInt(RegExp.$3,16)];
    };
    return "rgb("+rgb.join(",")+")";
}
getRGB('#00ff00');  //"rgb(0,255,0)"

第四章、對象

4.1 從數組到對象

用[]定義數組的方法咱們稱之爲數組文本標識法
用{}定義對象的方法咱們稱之爲對象文本標識法

4.1.2 哈希表、關聯型數組

在javascript中咱們用數組表示索引型數組,用對象表示關聯型數組

4.1.3 訪問對象屬性

通常經過如下兩種方式訪問對象的屬性:

  • 中括號表示法:hero['name']
  • 點號表示法:hero.name
4.1.7 構造器函數
function Hero(name){  //構造器函數首字母大寫
    this.name = name;
    this.occupation = 'ninja'
}
var hero = new Hero('jesse'); //使用new操做符建立新對象
hero.name;   //ninja

使用構造器函數的好處是能利用同一個構造器函數經過傳參從而建立出不一樣的對象。

4.1.8 全局對象

事實上程序所在的宿主環境通常都會爲其提供一個全局對象,
而所謂的全局變量其實只不過是該對象的屬性

4.1.9 構造器屬性

構造器屬性其實是一個指向用於建立該對象的構造器函數的引用

hero.contructor //Hero

經過instanceof操做符,咱們能夠測試一個對象是否是由某個指定的構造器函數所建立的

hero instanceof Hero; //true

4.1.12 傳遞對象

引用類型,由於其值大小不固定,所以棧內存中存放的只是該對象的訪問地址,(即該對象的引用)
堆內存爲這個值分配空間。所以咱們在引用上所作的任何改動,都會影響到他所引用的源對象。

4.2 內建對象

4.2.1 Object

全部對象都繼承自Object對象,所以都具備toLocaleString()、toString()和valueOf()方法。

var o = new Object();
var o = {};
alert(o); //[object,Object]

因爲alert()要接收字符串參數,因此它會在後臺調用toString()方法

Object構造器的成員:

Object構造器的成員

用Object()構造器所建對象的成員:

用Object()構造器所建對象的成員
用Object()構造器所建對象的成員
用Object()構造器所建對象的成員

4.2.2 Array
var a = new Array();
var a = [];
typeof a; //'object' 數組也是對象

值得關注的數組的屬性與方法

  • length屬性:定義數組時會自動生成length屬性,而通常對象中沒有
  • sort()、join()、slice()、splice()

Array對象的成員:

Array對象的成員
Array對象的成員
Array對象的成員
Array對象的成員

4.2.3 Function

函數實際上也是一種對象,函數對象的內建構造器是Function()

定義函數的三種方式:

  • function sum(a,b){return a + b;}; //函數聲明
  • var sum = function(a,b){return a + b;}; //函數表達式
  • var sum = new Function('a','b','return a + b;'); //Function構造器 避免使用
4.2.3.1 Function對象的屬性:
  • prototype屬性詳見第五章
  • length:用於記錄該函數所擁有的參數數量
  • caller:返回一個調用該函數對象的外層函數引用
function A(){return A.caller;}
function B(){return A();}
B();  //function B(){return A();}
4.2.3.2 Function對象的方法

Function對象繼承自Object對象,默認擁有Object對象的全部方法

call()、apply()方法都能讓對象去借用其餘對象中的方法爲己所用,這也是一種代碼重用的方式。

  • call()方法:
var someObj = {
    name: 'Ninja',
    say: function(who){
        return 'Hello '+who+', my name is '+ this.name;
    }
};
var myObj = {
    name:'Jesse'
};
someObj.say.call(myObj, 'Dude');//"Hello Dude, my name is Jesse"
//當say()被調用時其中的this就被自動設置成myObj對象的引用

若是咱們調用call方法時須要傳遞更多的參數,能夠在後面依次加入他們

someObj.say.call(myObj,'a','b','c')

若是咱們沒有將對象傳遞給call()的首參數,或者傳遞的是null,則它的調用對象默認爲全局對象

  • apply()方法:
    apply()的工做方式與call()基本相同,惟一的不一樣之處在於第二個參數的傳遞形式apply()方法的第二個參數是經過一個數組來傳遞的

someObj.say.apply(myObj,['a','b','c'])

4.2.3.3 從新認識arguments對象
  1. 在函數中經過arguments訪問傳遞給函數的全部參數
  2. arguments對象的callee屬性,該屬性返回的是當前被調用的函數對象
  3. 經過arguments.callee屬性實現匿名函數的遞歸調用
(function(count){
    if(count < 5){
        console.log(count);
        arguments.callee(++count);
    }
})(1)  //1,2,3,4

Function對象的成員

Function對象的成員
Function對象的成員

4.2.4 Boolean
var b = new Boolean();
typeof b;  //'object'
typeof b.valueOf();// 'boolean'
4.2.5 Number

Number對象的toString()方法有一個可選的radix參數(默認10)

var n =new Number(255);
n.toString(16); // 'ff'

Number()構造器的成員
Number()構造器的成員
Number()構造器的成員

Number對象的成員
Number對象的成員
Number對象的成員

4.2.6 String

當咱們將一個基本字符串當作對象來使用時,後臺會執行相應的String對象建立操做

String()構造器的成員
String()構造器的成員

String對象的成員
String對象的成員
String對象的成員
String對象的成員
String對象的成員

4.2.7 Math

Math對象既不能當作通常函數來使用,也不能用new操做符建立對象,只是一個包含一系列方法和屬性的內建對象

獲取某個max和min之間的值,公式((max-min)*Math.random())+min

Math對象的成員
Math對象的成員
Math對象的成員

4.2.8 Date

Date()構造器成員
Date()構造器成員

Date對象的成員
Date對象的成員
Date對象的成員
Date對象的成員
Date對象的成員
Date對象的成員

4.2.9 RegExp
var reg = new RegExp('j.*t');
var reg = /j.*t/; //匹配任何以j開頭t結尾的字符串,且這倆字符之間包含1個或多個字符
4.2.9.1 RegExp對象的屬性
  • global:若是該值爲false(默認),相關搜索在找到第一個匹配位置時就會中止,若是爲true則會找出全部匹配位置,簡寫爲‘g’
  • ignoreCase:設置是否忽略大小寫,默認爲false,簡寫爲'i'
  • multiline:設置是否跨行搜索,默認爲false,簡寫爲'm'
  • lastIndex:搜索開始的索引位置,默認爲0。在對象建立以後能夠修改
  • source:用於存儲正則表達式匹配模式

var reg = /j.*t/img;

4.2.9.2 RegExp對象的方法
  • test():返回的是一個布爾值(找到匹配內容爲true,不然爲false)
  • exec():返回的是一個由匹配字符串組成的數組
/j.*t/i.test('Javascript')   //true  
/j.*t/i.exec('Javascript')[0]  //Javascript
4.2.9.3 以正則表達式爲參數的字符串方法
  • match():返回的是一個包含匹配內容的數組
  • search():返回的是第一個匹配內容所在的位置
  • replace():將匹配的文本替換成指定的字符串
  • split():根據指定的正則表達式將目標字符串分割成若干數組元素
var s = new String('HelloJavascriptWorld');
s.match(/j.*a/ig);  //['Java']
s.search(/j.*a/i);  //5
//當某個匹配對象被找到時,若是咱們想讓相關的替換字符串中包含匹配的文本,可使用$&修飾符
s.replace(/[A-Z]/g,'_$&');  //"_Hello_Javascript_World"
//若是正則表達式分了組(即帶括號),那麼能夠用$1表明匹配分組中的第一組,$2表明第二組
s.replace(/[A-Z]/g,'_$1'); //"_Hello_Javascript_World"
var csv = 'one, two,three ,four';
csv.split(/\s*,\s*/)  //["one", "two", "three", "four"]
// \s*匹配0個或多個空格
//以上的4個方法能夠接受的參數也包括字符串
"test".replace('t','r');  //"rest"

RegExp對象的成員
RegExp對象的成員
RegExp對象的成員

4.2.10 Error對象
try{
    //可能會致使錯誤的代碼
}catch(e){
    //在發生錯誤時處理代碼
}finally{  //可選的
    //不管如何都會執行的代碼
}

4.4 練習題

c = [1,2,[1,2]];
c.sort(); //[1, [1,2], 2]

四、在String()構造器不存在時,自定義MyString()構造器函數並經過如下測試

function MyString(string){
    //this.length = 
    this.toString = function(){
        return string.toString();
    }
    this.valueOf = function(){
        return string.valueOf();
    }
    this.reverse = function(){
        return Array.prototype.reverse.apply(string.split('')).join('');
    }
}
var s = new MyString('hello');
s.length;  //5
s[0]; //'h'
s.toString(); //'hello'
s.valueOf(); //'hello'
s.chatAt(1); //'e'
s.concat(' world!'); //'hello world!'
s.slice(0,-1); //'hell'
s.split('l'); //['he','','o']

六、在Array()不存在時,建立MyArray()構造器並經過如下測試

var a = new MyArray(1,2,3,'test');
a.length;//4
a.toString();//'1,2,3,test'
a[a.length - 1];//'test'
a.push('boo');//5
a.pop();//'1,2,3,test'
a.join(',');//'1,2,3,test'
function MyArray(){
    this.length = 
}

第五章、原型

5.1 原型屬性

5.1.4 利用自身屬性重寫原型屬性

若是在一個對象自身屬性中沒有找到指定的屬性,就能夠去原型鏈中查找相關屬性。可是若是趕上對象自身屬性與原型鏈屬性同名時,那麼對象自身屬性的優先級高於原型鏈屬性。

function Gadget(name,color){
    this.name = name;
    this.color = color;
    this.method =function(){
        return 1;
    }
}
Gadget.prototype.price = 10;
Gadget.prototype.rating = 3;
var newtoy = new Gadget('webcam','back');
for(var prop in newtoy){
    console.log(prop + '=' + newtoy[prop]);
}
//name=webcam
//color=back
//method=function (){return 1;}
//price=10
//rating=3

hasOwnProperty()方法用於區分對象自身屬性(返回true)與原型屬性(返回false)

newtoy.hasOwnProperty('name');   //true
newtoy.hasOwnProperty('price');  //false

propertyIsEnumerable()方法對全部非內建對象屬性返回true,表示可經過for-in枚舉;

newtoy.propertyIsEnumerable('name'); //true

isPrototypeOf()方法會告訴咱們當前對象是不是另外一個對象的原型

var monkey = {
    hair:true,
    feeds:'bananas',
    breathes:'air'
};
function Human(name){
    this.name = name;
}
Human.prototype = monkey;
var jesse = new Human('Jesse');
monkey.isPrototypeOf(jesse);  //true

5.2 擴展內建對象

爲Array對象添加inArray()方法,用於查詢數組中是否存在某個特定的值

if(!Array.prototype.inArray){  //若是想經過原型爲某個對象添加新屬性,請務必檢查該屬性是否已存在
    Array.prototype.inArray = function (needle){
        for(var i = 0;i < this.length; i++){
            if(this[i] == needle){
                return true;
            }
        }
        return false;
    }
}
var a = ['a','b','c'];
a.inArray('d');  //false

爲String對象添加reverse()方法,用於反向輸出該字符串

if(!String.prototype.reverse){  //若是想經過原型爲某個對象添加新屬性,請務必檢查該屬性是否已存在
    String.prototype.reverse = function(){
        return Array.prototype.reverse.apply(this.split('')).join('');
    }
}
"Jesse".reverse();  //"esseJ"
//首先利用this.split('')將目標字符串轉爲數組,並做爲apply()的第二個參數,第一個參數不傳值時默認爲全局對象
//再調用數組的reverse()方法生成反向數組
//最後經過join()方法將數組轉化爲字符串
5.2.2 原型陷阱
  • 當咱們對原型對象徹底替換時,可能會觸發異常
  • prototype.constructor屬性不可靠

解決方法:當咱們重寫某對象的prototype時,必須重置相應的constructor屬性

5.4 練習題

var shape = {
    type:"triangle",
    getType:function(){
        return this.type;
    }
}
function Triangle(a,b,c){
    this.a = a;
    this.b = b;
    this.c = c;
}
Triangle.prototype = shape;
//當咱們重寫某對象的prototype時,必須重置相應的constructor屬性
Triangle.prototype.constructor = Triangle;
Triangle.prototype.getPerimeter = function(){
    return this.a + this.b + this.c;
}
var t = new Triangle(1,2,3);
for(var prop in t){
    if(t.hasOwnProperty(prop)){
        console.log(prop + '=' + t[prop]);
    }
}
t.constructor; //Trianle(a,b,c)
shape.isPrototypeOf(t); //true
t.getPerimeter(); //6
t.getType(); //"triangle"

第六章、繼承

6.1 原型鏈

6.1.1 原型鏈示例
function Shape(){
    this.name = 'shape';
    this.toString = function(){return this.name;};
}
function TwoDShape(){
    this.name = '2D shape';
}
function Triangle(side,height){
    this.name = 'Triangle';
    this.side = side;
    this.height = height;
    this.getArea = function(){
        return this.side*this.height/2;
    }
}
TwoDShape.prototype = new Shape();
Triangle.prototype = new TwoDShape();
//咱們用構造器Shape()另建了一個新的實體,而後用它去覆蓋該對象的原型
//這確保了在繼承實現以後,咱們對Shape()所進行的任何修改、重寫、刪除都不會對TwoShape()產生影響
TwoDShape.prototype.constructor = TwoDShape;
Triangle.prototype.constructor = Triangle;
var my = new Triangle(5,10);
my.getArea();//25
my.toString(); // Triangle
6.1.2 將共享屬性遷移到原型中
function Shape(){};
Shape.prototype.name = 'shape';
Shape.prototype.toString = function(){return this.name;};
function TwoDShape(){};
TwoDShape.prototype = new Shape();
TwoDShape.prototype.constructor = TwoDShape;
//咱們須要在對原型對象進行擴展以前,先完成相關繼承關係的構建
TwoDShape.prototype.name = '2D shape';
function Triangle(side,height){
    this.side = side;
    this.height = height;
}
Triangle.prototype = new TwoDShape();
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){
    return this.side*this.height/2;
}

6.2 只繼承於原型

function Shape(){};
Shape.prototype.name = 'shape';
Shape.prototype.toString = function(){return this.name;};
function TwoDShape(){};
//TwoDShape.prototype = new Shape(); new Shape()會將Shape的屬性設定爲對象自身屬性,這樣的代碼是不可重用的
TwoDShape.prototype = Shape.prototype;
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = '2D shape';
function Triangle(side,height){
    this.side = side;
    this.height = height;
}
Triangle.prototype = TwoDShape.prototype;
//這樣當然能夠提升效率,可是子對象和父對象都指向同一對象,一旦對原型屬性進行修改,繼承的對象相關屬性也隨之改變
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){
    return this.side*this.height/2;
}
var s = new Shape();
s.name;//"Triangle"

6.3 uber--子對象訪問父對象的方式

在構建繼承關係的過程當中引入一個uber屬性,並令其指向其父級原型對象

6.8 深拷貝

當對象類型的屬性拷貝時,實際上拷貝的只是該對象在內存中的位置指針,這一過程就是淺拷貝

//淺拷貝
function extendCopy(p){
    var c = {};
    for(var i in p){
        c[i] = p[i];
    }
    c.uber = p;
    return c;
}
//深拷貝
function deepCopy(p,c){
    var c = c || {};
    for(var i in p){
        if(typeof p[i] === 'object'){ 
            c[i] = (p[i].constructor == Array) ? [] : {};
            deepCopy(p[i],c[i]); //在遇到一個對象引用型的屬性時,須要再次調用深拷貝
        }else{
            c[i] = p[i];
        }
    }
    return c;
}
var parent = {
    numbers:[1,2,3],
    letters:['a','b','c'],
    obj:{prop:1},
    bool:true
};
var mydeep = deepCopy(parent);
var myshallow = extendCopy(parent);
mydeep.numbers.push(4,5,6); //6
mydeep.numbers; //[1, 2, 3, 4, 5, 6]
parent.numbers; //[1, 2, 3]
myshallow.numbers.push(10); //4
myshallow.numbers; //[1, 2, 3, 10]
parent.numbers; //[1, 2, 3, 10]
mydeep.numbers; //[1, 2, 3, 4, 5, 6]

6.9 object

基於在對象之間直接構建繼承關係的理念,能夠用object()來接收父對象,並返回一個以該父對象爲原型的
新對象。

function object(p){
    function F(){};
    F.prototype = p;
    return new F();
}

6.12 寄生式繼承

var twoD = {
    name:'2d shape',
    dimensions:2
}
function triangle(s,h){
    var that = object(twoD);//把twoD對象全屬性拷貝進that對象
    that.name = 'Triangle';
    that.getArea = function(){return this.side * this.height / 2};
    that.side = s;
    that.height = h;
    return that;
}

6.14 本章小結

實現繼承的方法大體上分爲兩類:

  • 基於構造器工做模式
  • 基於對象工做模式

實現繼承的方法
實現繼承的方法
實現繼承的方法

6.15 案例學習:圖形繪製

未完成

第七章、瀏覽器環境

7.3 BOM

7.3.1 Window對象
window.open('新URL','新窗口名','以逗號分割的功能性列表')
window.close();
window.moveTo(x,y);
window.moveBy(x,y);
window.resizeTo(x,y);
window.resizeBy(x,y);
window.alert();
window.prompt(); //點擊確認返回相應文本,點擊取消返回null
window.confirm();//點擊確認返回true,點擊取消返回false
window.setTimeout();//指定多長時間後執行代碼
window.setInterval();//指定每隔多長時間執行代碼

navigation.userAgent是一個用戶瀏覽器識別的長字符串,但不要過度依賴這種用戶代理字符串,
瀏覽器能力檢測是更好地選擇

  • 這種字符串很難追蹤到全部的瀏覽器以及其各類版本
  • 這種字符串能夠被修改
7.3.3 location對象

localtion對象的完整屬性:

  • href
  • hash
  • host
  • hostname
  • port
  • protocol
  • search

location對象的方法:

  • reload()重載某頁面
  • assign()打開新URL,並在歷史記錄中生成新紀錄
  • replace()與assign()相同,但不會生成新紀錄
7.3.4 history對象

history.forward();history.back();

7.3.5 screen對象
screen.width();
screen.availwidth();

7.4 DOM

7.4.2 DOM節點的訪問
hasChildNodes()方法用於判斷一個節點是否存在子節點
hasAttributes()方法用於檢查該元素中書否存在屬性
document.documentElement.childNodes.length; //2
//任何節點均可以經過自身的parentNode來訪問它的父節點
document.documentElement.parentNode; //<html>
document.getElementsByTagName();
document.getElementsByName();
document.getElementById();
nextSibling/previousSibling;
firstChild/lastChild
7.4.4 新建節點
createElement();
var myp = document.createElement('p');
createTextNode();//新建文本節點
appendChild();
document.body.appendChild(myp);
cloneNode(true)//true深拷貝 false淺拷貝
insertBefore(要插入的節點,參照節點);
replaceChild(要插入的節點,要替換的節點)
removeChild(要移除的節點);

7.5 事件

7.5.3 DOM的事件監聽器
addEventListener('事件類型',函數指針[,false]);
removeEventListener('事件類型',函數指針[,false]);
//匿名函數所定義的監聽器是不能被移除的

該方法基於某一節點對象來調用,第三個參數決定代碼是否採用事件捕捉,可選的,爲了適應更多的瀏覽器,咱們通常將其設置爲false,即採用事件冒泡。

7.6 XMLHttpRequest對象

//建立xhr對象
var xhr;
if(window.XMLHttpRequest){
    xhr = new XMLHttpRequest();
}else{
    xhr = new ActiveXObject("Microsoft.XMLHTTP")
}
//設置一個能觸發readystatechange事件的事件監聽器,及處理響應程序
xhr.onreadystatechange=function(){
    if (xhr.readyState==4 && xhr.status==200){
        console.log(xhr.responseText);
    }
}
//open(請求類型,請求目標URL,是否異步請求)
xhr.open('GET','somefile.txt',true);
//發送請求
xhr.send('')

7.8 練習題

2.3
function include(js){
    var script = document.createElement('script');
    script.src = js;
    document.body.appendChild(script);
}
include('somescript.js');
3.1
var myevent = {
    addListener:function(el,type,fn){
        if(typeof window.addEventListener === 'function'){
            myevent.addListener = function(el,type,fn){
                el.addEventListener(type,fn,false);
            };
        }else if(typeof window.attachEvent === 'function'){ //code for IE
            myevent.addListener = function(el,type,fn){
                el.attachEvent('on'+type,fn);
            };
        }else{  // code for older browsers
            myevent.addListener = function(el,type,fn){
                el['on' + type] = fn;
            };
        }
        myevent.addListener(el,type,fn);
    },
    removeListener : function(el,type,fn){
        if(typeof window.removeEventListener === 'function'){
            myevent.removeListener = function(el,type,fn){
                el.removeEventEventListener(type,fn,false);
            };
        }else if(typeof window.detachEvent === 'function'){ //code for IE
            myevent.removeListener = function(el,type,fn){
                el.detachEvent('on'+type,fn);
            };
        }else{  // code for older browsers
            myevent.removeListener = function(el,type,fn){
                el['on' + type] = null;
            };
        }
        myevent.removeListener(el,type,fn);
    },
    getEvent:function(event){},
    getTarget:function(event){},
    stopPropagation:function(event){},
    preventDefault:function(event){}
}
4.1
var ajax ={
    request:function(url,requestType,queryString){
        var xhr;
        if(window.XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr = new ActiveXObject("Microsoft.XMLHTTP")
        }
        xhr.onreadystatechange = function(){
            if (xhr.readyState == 4 && xhr.status == 200){
                console.log(xhr.responseText);
            }
        }
        xhr.open(requestType,url,true);
        xhr.send('');
    }
}
ajax.request('some.txt','get');

第八章、編程模式與設計模式

8.1 編程模式

8.1.2 命名空間與初始化分支模式

爲了減小命名衝突,最好的辦法是將變量和方法定義在不一樣的命名空間中,這種方法的實質是隻定義一個全局變量,
並將其餘的方法和屬性定義爲該變量的屬性。

var mySpace = {};
mySpace.event = {
    addListener:null,
    removeListener:null
    ……
}
if(typeof window.addEventListener === 'function'){
    mySpace.event.addListener = function(el,type,fn){
        el.addEventListener(type,fn,false);
    };
    mySpace.event.removeListener = function(el,type,fn){
        el.removeEventListener(type,fn,false);
    };
}else if(typeof window.attachEvent === 'function'){ //code for IE
    mySpace.event.addListener = function(el,type,fn){
        el.attachEvent('on'+type,fn);
    };
    mySpace.event.removeListener = function(el,type,fn){
        el.detachEvent('on'+type,fn);
    };
}else{  // code for older browsers
    mySpace.event.addListener = function(el,type,fn){
        el['on' + type] = fn;
    };
    mySpace.event.removeListener = function(el,type,fn){
        el['on' + type] = null;
    };
}
8.1.4 延遲定義模式
var mySpace = {};
mySpace.event = {
    addListener:function(el,type,fn){
        if(typeof window.addEventListener === 'function'){
            mySpace.event.addListener = function(el,type,fn){
                el.addEventListener(type,fn,false);
            };
        }else if(typeof window.attachEvent === 'function'){ //code for IE
            mySpace.event.addListener = function(el,type,fn){
                el.attachEvent('on'+type,fn);
            };
        }else{  // code for older browsers
            mySpace.event.addListener = function(el,type,fn){
                el['on' + type] = fn;
            };
        }
        mySpace.event.addListener(el,type,fn);
    }
};
8.1.5 配置對象

該模式適用於有不少參數的函數或方法

用單個對象來替代多個參數有如下幾點優點:

  • 不用考慮參數的順序
  • 能夠跳過某些參數的設置
  • 函數的擴展性強
  • 代碼可讀性好
var myapp = {};
myapp.dom = {};
myapp.dom.Button = function(text,conf){
    var type = conf.type || 'submit';
    var font = conf.font || 'microsoftyahei';
    //……
}
//使用方法以下:
var config = {
    font:'Arial,Verdana,microsoftyahei',
    color:'#fff'
};
new myapp.dom.Button('lalala',config);
8.1.6 私有屬性和方法
8.1.7 特權函數
8.1.8 私有函數的公有化
8.1.9 自執行函數
(function(){
    // code in here
})()
//該模式特寫適用於某些腳本加載時所執行的一次性初始化工做
8.1.10 鏈式調用

構造器返回的是新建對象的this指針,咱們可使用這些方法所返回的實例來調用其餘方法

document.body.appendChild(
    new mySpace.dom.Element('span')
               .setText('hello')
               .setStyle('color','red')
);
8.1.11 JSON

var obj = JSON.parse(xhr.responseText);

8.2 設計模式

8.2.2 單件模式
8.2.3 工廠模式
8.2.4 裝飾器模式
8.2.5 觀察者模式
相關文章
相關標籤/搜索