javascript高級編程

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>無標題文檔</title>
<script type="text/javascript">

    var array=[1,2,3,4,5,6];
    var arr=array.map(function(item){
            return item*2;
        });
    alert(arr[0]);// 2
------------------------------------------------
    /////變量的做用域
    var variable="out";
    
    function func()
    {
        variable="in";
        alert(variable); 
    }
    func();              // 打印"in"
    alert(variable);   // 打印"in"
------------------------------------------------
    var object={
            field:"self",
            printInfo:function(){
                alert(this.field);    
            }
        }
    alert(object.field);  //"self"
    object.printInfo(); // "self"
    for(var key in object){
        alert(key+" : "+object[key]);
    }
------------------------------------------------
///JavaScript對象
    function Base(name) {
        this.name = name;
        this.getName = function () {
            return this.name;
        }
    }
    function Child(id) {
        this.id = id;
        this.getId = function () {
            return this.id;
        }
    }
    //將Child原型指向一個新的base對象
    Child.prototype = new Base("base");

    //實例化一個Child對象
    var c1 = new Child("child");
    //調用c1自己的getId方法
    alert(c1.getId()); //child
    //因爲c1從原型鏈上「繼承」到了getName方法,所以能夠訪問
    alert(c1.getName()); //base
    //////註解:因爲遍歷原型鏈時是由下而上的,因此最早遇到的屬性值最早返回

    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.getName = function () {
            return this.name;
        }
        this.getAge = function () {
            return this.age;
        }
    }
    var tom = new Person("Tom", 30);
    var jerry = new Person("jerry", 40);
    ////註解:經過原型鏈,能夠實現繼承/重載等面向對象的js代碼。固然這個機制並不是基於類,而是基於原型
------------------------------------------------
    //定義個「類」,Address
    function Address(street, xno) {
        this.street = street || "黃泉路";
        this.xno = xno || 135;
        this.toString = function () {
            return "street:" + this.street + ",No:" + this.xno;
        }
    }
    //定義另一個「類」,Person
    function Person(name,age,addr){
        this.name = name || "未知";
        this.age = age;
        this.addr = addr || new Address(null, null);
        this.getName = function () {
            return this.name;
        };
        this.getAge = function () {
            return this.age;
        };
        this.getAddr = function () {
            return this.addr.toString();
        };
    }
    //經過new 操做符來建立兩個對象,注意,這個兩個對象是相互獨立的實體
    var jack = new Person("jack", 26, new Address("青海路", 123));
    var abruzzi = new Person("abruzzi", 26);
    //查看結果
    alert(jack.getName()); //jack
    alert(jack.getAge());  //26
    alert(jack.getAddr()); //street:青海路,No:123

    alert(abruzzi.getName()); //abruzzi
    alert(abruzzi.getAge());   //26
    alert(abruzzi.getAddr());  //street:黃泉路,No:135
------------------------------------------------
    ////函數做用域
    var str = "global";
    function scopeTest() {
        alert(str);
        var str = "local";
        alert(str);
    }
    scopeTest();
    //運行結果   undefined     local
    ///註解:由於在函數scopeTest的定義中,預先訪問了未聲明的變量str,而後纔對str變量進行初始化,因此第一個alert會返回undefined錯誤。
    ///那爲何函數這個時候不會去訪問外部的str變量呢?
    ///這是由於在詞法分析結束後,構造做用域的時候會將函數內定義的var變量放入該鏈,所以str在整個函數內部是可見的(從函數體的第一行到最後一行),
    ///因爲str變量自己是未定義的,程序順序執行,到第一行就會返回爲定義,第二行爲str賦值
------------------------------------------------
    /////閉包
    ///因爲在javaScript中,函數是對象,對象是屬性集合,而屬性的值有能夠是對象,則在函數內定義函數成爲理所固然,若是在函數func內部聲明函數inner,而後在函數外調用inner,這個過程即產生閉包。
    var outter = [];
    function clouseTest() {
        var array = ["one", "two", "three", "four"];
        for (var i = 0; i < array.length; i++) {
            var x = {};
            x.no = i;
            x.text = array[i];
            x.invoke = function () {
                alert(i);
            }
            outter.push(x);
        }
    }
    //調用
    clouseTest();
    outter[0].invoke();
    outter[1].invoke();
    outter[2].invoke();
    outter[3].invoke();
    ///運行結果是  4   4   4   4   爲何不是0   1   2   3呢?
    //由於每次在迭代的時候,語句x.invoke=function(){alert(i);}並無被執行,只是構建了一個函數體爲「alert(i);」的函數對象而已。
    //若是每次迭代的時候語句x.invoke=function(){alert(i);}執行的話,則調用clouseTest()的時候則就會彈出對話框了,事實上卻沒有彈,證實沒有執行
    //如何解決呢?
    var outter = [];
    function clouseTest2() {
        var array = ["one", "two", "three", "four"];
        for (var i = 0; i < array.length; i++) {
            var x = {};
            x.no = i;
            x.text = array[i];
            x.invoke = function (no) {
                alert(no);
            }(i);//調用
            outter.push(x);
        }
    }
    //調用
    clouseTest2();
------------------------------------------------
    ///封裝
    var person = function () {
        //變量的做用域爲函數內部,外部沒法訪問
        var name = "張飛";
        return {
            getName: function () { return name; },
            setName: function (newName) { name = newName; }
        }
    }();
    alert(person.name);//直接訪問,結果爲undefined
    alert(person.getName());  //張飛
    person.setName("關羽");
    alert(person.getName());  //關羽

    function Person() {
        var name = "張飛";
        return {
            getName: function () { return name; },
            setName: function (newName) { name = newName; }
        }
    };
    var john = new Person();
    alert(john.getName());  //張飛
    john.setName("john");
    alert(john.getName());  // john
    ////在不一樣的Javascript解釋器實現中,因爲解釋器自己的缺陷,使用閉包可能形成內存泄露(嚴重影響用戶體驗)
    ///如:對象A引用B,B引用C,而C又引用A
------------------------------------------------
    ///【面向對象的JavaScript】
    //原型繼承:js中的繼承能夠經過原型鏈來實現,調用對象上的一個方法,因爲方法在javascript對象中是對另外一個函數對象的引用,所以解釋器會在對象中查找該屬性,
    //若是沒有找到,則在其內部對象prototype對象上搜索。因爲prototype對象與對象自己的結構是同樣的,所以這個過程會一直回溯到發現該屬性,不然,報錯
    function Base() {
        this.baseFunc = function () { alert("基礎行爲");}
    }
    function Middle() {
        this.middleFunc = function () { alert("中間行爲");}
    }
    
    Middle.prototype = new Base();

    function Final() {
        this.finalFunc = function () { alert("最終行爲");}
    }
    Final.prototype = new Middle();

    function Test() {
        var obj = new Final();
        obj.baseFunc();
        obj.middleFunc();
        obj.finalFunc();
    }
    Test();/////  基礎行爲   中間行爲   最終行爲 
    // 原型鏈示意圖 見圖  P76 

    ///new 操做符
    function Shape(type) {
        this.type = type || "rect";
        this.calc = function () { return "calc," + this.type;}
    }
    var triangle = new Shape("triangle");
    alert(triangle.calc());

    var circle = new Shape("circle");
    alert(circle.calc());
    ////註解:Javascript和其餘面向對象的new操做符不同,triangle,circle可能在Java中是Shape對應的具體對象,可是在js中並不是如此(new比較特殊)
    ////首先,建立一個空對象,而後用函數apply方法,將這個空對象傳入做爲apply的第一個參數以及上下文參數,這樣的函數內部的this將會被這個空的對象所替代。
    var triangle = new Shape("triangle");
    ///至關於下面的代碼
    var triangle = {};
    Shape.apply(triangle, ["triangle"]);
------------------------------------------------
    ///柯里化
    //柯里化就是餘下將函數的某些參數傳入,獲得一個簡單的函數,可是預先傳入的參數被保存在閉包中,所以會有一些奇特的特性
    var addr = function (num) {
        return function (y) { return num + y;}
    }
    var inc = addr(1);
    var dec = addr(-1);

    alert(inc(99));  //100
    alert(dec(101));  // 100

    alert(addr(100)(2)); // 102
    alert(addr(2)(100)); // 102
------------------------------------------------
    //開發智力(坑爹)
    //函數的不動點
    function fixedPoint(Func, first) {
        var tolerance = 0.00001;
        function closeEnough(x, y) {
            return Math.abs(x - y) < tolerance;
        };
        function Try(guess) {
            var next = Func(guess);
            //alert(next+" "+ guess);
            if (closeEnough(guess, next)) {
                return next;//返回小的
            }
            else {
                return Try(first);//遞歸調用
            }
        };
        return Try(first);
    }
    //數層嵌套函數
    function sqrt(x) {
        var Func = function (y) {
            var div = function (a, b) { return (a + b) / 2; }
            return div(y, x / y);
        }
        return fixedPoint(Func, 1.0);
    }
    alert(sqrt(100));
------------------------------------------------///原型鏈:因爲原型對象自己也是對象,它也有本身的原型,而他本身的原型對象又能夠有本身的原型,這樣就組成了一條鏈,這個鏈就是原型鏈
    ///Javascript引擎在訪問對象的屬性時,若是在對象自己中沒有找到,則會去原型鏈中查找,若是找到,直接返回值,若是整個鏈都遍歷且沒有找到屬性,則返回undefined。原型鏈通常是實現爲一個鏈表,這樣就能夠按照必定的順序來查找
    var base = {
        name: "base",
        getInfo: function () {
            return this.name;
        }
    }
    var ext1 = {
        id: 0,
        __proto__:base
    }
    var ext2 = {
        id: 9,
        __proto__:base
    }
    alert(ext1.id);      //0
    alert(ext1.getInfo()); //base
    alert(ext2.id);    //9
    alert(ext2.getInfo()); // base
    //原型鏈圖 見P105
    var base = {     ///(原型對象)
        name: "base",
        getInfo: function () { return this.id + " : " + this.name;}
    };
    var ext1 = {   ///(原始對象)
        id: 0,
        __proto__:base
    };
    alert(ext1.getInfo()); // 0 : base
    ///註解:getInfo函數中的this表示原始的對象,並不是原型對象,上例中的id屬性來自於ext1對象,而name來自base對象
    ///若是沒有顯示的聲明本身的」__proto__「屬性,這個值默認的設置爲Object.prototype,而Object.prototype的「__proto__」屬性值爲「null」,標誌着原型鏈的終結
------------------------------------------------
    ///執行期上下文:按照ECMAScript的規範,一共有三種類型的代碼,全局代碼、函數代碼、以及eval代碼
    ///this上下文:ECMAScript的規範中對this的定義爲:this是一個特殊的對象,與執行期上下文相關,所以能夠稱爲上下文對象。
    ///this是執行期上下文對象的一個屬性(執行期上下文對象包括變量對象、做用域鏈以及this)。執行期上下文對象有三類,當進入不一樣的上下文時,this的值會肯定下來,而且this的值不能更改。
    ///在執行全局代碼時,控制流會進入全局執行期上下文,而在執行函數時,又會有函數執行期上下文
    var global = this;
    var tom = {
        name: "Tom",
        home: "desine",
        getInfo: function () {
            alert(this.name + ", from " + this.home);
        }
    };
    tom.getInfo();   // Tom,from desine

    var jerry = {
        name: "Jerry",
        getInfo:tom.getInfo
    };
    jerry.getInfo();   // Jerry,from undefined
    
    global.getInfo = tom.getInfo;
    global.getInfo();   // ,from undefined
</script>
</head>

<body>
</body>
</html>
相關文章
相關標籤/搜索