<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    jasmine214--love

    只有當你的內心總是充滿快樂、美好的愿望和寧靜時,你才能擁有強壯的體魄和明朗、快樂或者寧靜的面容。
    posts - 731, comments - 60, trackbacks - 0, articles - 0

    Javascript--this用法

    Posted on 2010-06-27 19:50 幻海藍夢 閱讀(337) 評論(0)  編輯  收藏 所屬分類: JS

    原文:http://www.cnblogs.com/sanshi/archive/2009/07/08/1519251.html
    這一章我們將會重點介紹JavaScript中幾個重要的屬性(this、constructor、prototype), 這些屬性對于我們理解如何實現JavaScript中的類和繼承起著至關重要的作用。

    this

    this表示當前對象,如果在全局作用范圍內使用this,則指代當前頁面對象window; 如果在函數中使用this,則this指代什么是根據運行時此函數在什么對象上被調用。 我們還可以使用apply和call兩個全局方法來改變函數中this的具體指向。

    先看一個在全局作用范圍內使用this的例子:

            <script type="text/javascript">
                console.log(this === window);  // true
                console.log(window.alert === this.alert);  // true
                console.log(this.parseInt("021", 10));  // 10
            </script>
            

    ?

    函數中的this是在運行時決定的,而不是函數定義時,如下:

            // 定義一個全局函數
            function foo() {
                console.log(this.fruit);
            }
            // 定義一個全局變量,等價于window.fruit = "apple";
            var fruit = "apple";
            // 此時函數foo中this指向window對象
            // 這種調用方式和window.foo();是完全等價的
            foo();  // "apple"
    
            // 自定義一個對象,并將此對象的屬性foo指向全局函數foo
            var pack = {
                fruit: "orange",
                foo: foo
            };
            // 此時函數foo中this指向window.pack對象
            pack.foo(); // "orange"
            

    ?

    全局函數apply和call可以用來改變函數中this的指向,如下:

            // 定義一個全局函數
            function foo() {
                console.log(this.fruit);
            }
            
            // 定義一個全局變量
            var fruit = "apple";
            // 自定義一個對象
            var pack = {
                fruit: "orange"
            };
            
            // 等價于window.foo();
            foo.apply(window);  // "apple"
            // 此時foo中的this === pack
            foo.apply(pack);    // "orange"
            
    注:apply和call兩個函數的作用相同,唯一的區別是兩個函數的參數定義不同。

    ?

    因為在JavaScript中函數也是對象,所以我們可以看到如下有趣的例子:

            // 定義一個全局函數
            function foo() {
                if (this === window) {
                    console.log("this is window.");
                }
            }
            
            // 函數foo也是對象,所以可以定義foo的屬性boo為一個函數
            foo.boo = function() {
                if (this === foo) {
                    console.log("this is foo.");
                } else if (this === window) {
                    console.log("this is window.");
                }
            };
            // 等價于window.foo();
            foo();  // this is window.
            
            // 可以看到函數中this的指向調用函數的對象
            foo.boo();  // this is foo.
            
            // 使用apply改變函數中this的指向
            foo.boo.apply(window);  // this is window.
            

    ?

    prototype

    我們已經在第一章中使用prototype模擬類和繼承的實現。 prototype本質上還是一個JavaScript對象。 并且每個函數都有一個默認的prototype屬性。
    如果這個函數被用在創建自定義對象的場景中,我們稱這個函數為構造函數。 比如下面一個簡單的場景:

            // 構造函數
            function Person(name) {
                this.name = name;
            }
            // 定義Person的原型,原型中的屬性可以被自定義對象引用
            Person.prototype = {
                getName: function() {
                    return this.name;
                }
            }
            var zhang = new Person("ZhangSan");
            console.log(zhang.getName());   // "ZhangSan"
            
    作為類比,我們考慮下JavaScript中的數據類型 - 字符串(String)、數字(Number)、數組(Array)、對象(Object)、日期(Date)等。 我們有理由相信,在JavaScript內部這些類型都是作為構造函數來實現的,比如:
            // 定義數組的構造函數,作為JavaScript的一種預定義類型
            function Array() {
                // ...
            }
            
            // 初始化數組的實例
            var arr1 = new Array(1, 56, 34, 12);
            // 但是,我們更傾向于如下的語法定義:
            var arr2 = [1, 56, 34, 12];
            
    同時對數組操作的很多方法(比如concat、join、push)應該也是在prototype屬性中定義的。
    實際上,JavaScript所有的固有數據類型都具有只讀的prototype屬性(這是可以理解的:因為如果修改了這些類型的prototype屬性,則哪些預定義的方法就消失了), 但是我們可以向其中添加自己的擴展方法。
            // 向JavaScript固有類型Array擴展一個獲取最小值的方法
            Array.prototype.min = function() {
                var min = this[0];
                for (var i = 1; i < this.length; i++) {
                    if (this[i] < min) {
                        min = this[i];
                    }
                }
                return min;
            };
            
            // 在任意Array的實例上調用min方法
            console.log([1, 56, 34, 12].min());  // 1
            

    注意:這里有一個陷阱,向Array的原型中添加擴展方法后,當使用for-in循環數組時,這個擴展方法也會被循環出來。
    下面的代碼說明這一點(假設已經向Array的原型中擴展了min方法):
            var arr = [1, 56, 34, 12];
            var total = 0;
            for (var i in arr) {
                total += parseInt(arr[i], 10);
            }
            console.log(total);   // NaN
            
            
    解決方法也很簡單:
            var arr = [1, 56, 34, 12];
            var total = 0;
            for (var i in arr) {
                if (arr.hasOwnProperty(i)) {
                    total += parseInt(arr[i], 10);
                }
            }
            console.log(total);   // 103
            

    ?

    constructor

    constructor始終指向創建當前對象的構造函數。比如下面例子:

            // 等價于 var foo = new Array(1, 56, 34, 12);
            var arr = [1, 56, 34, 12];
            console.log(arr.constructor === Array); // true
            // 等價于 var foo = new Function();
            var Foo = function() { };
            console.log(Foo.constructor === Function); // true
            // 由構造函數實例化一個obj對象
            var obj = new Foo();
            console.log(obj.constructor === Foo); // true
            
            // 將上面兩段代碼合起來,就得到下面的結論
            console.log(obj.constructor.constructor === Function); // true
            

    ?

    但是當constructor遇到prototype時,有趣的事情就發生了。
    我們知道每個函數都有一個默認的屬性prototype,而這個prototype的constructor默認指向這個函數。如下例所示:

            function Person(name) {
                this.name = name;
            };
            Person.prototype.getName = function() {
                return this.name;
            };
            var p = new Person("ZhangSan");
            
            console.log(p.constructor === Person);  // true
            console.log(Person.prototype.constructor === Person); // true
            // 將上兩行代碼合并就得到如下結果
            console.log(p.constructor.prototype.constructor === Person); // true
            
    當時當我們重新定義函數的prototype時(注意:和上例的區別,這里不是修改而是覆蓋), constructor的行為就有點奇怪了,如下示例:
            function Person(name) {
                this.name = name;
            };
            Person.prototype = {
                getName: function() {
                    return this.name;
                }
            };
            var p = new Person("ZhangSan");
            console.log(p.constructor === Person);  // false
            console.log(Person.prototype.constructor === Person); // false
            console.log(p.constructor.prototype.constructor === Person); // false
            
    為什么呢?
    原來是因為覆蓋Person.prototype時,等價于進行如下代碼操作:
            Person.prototype = new Object({
                getName: function() {
                    return this.name;
                }
            });
            
    而constructor始終指向創建自身的構造函數,所以此時Person.prototype.constructor === Object,即是:
            function Person(name) {
                this.name = name;
            };
            Person.prototype = {
                getName: function() {
                    return this.name;
                }
            };
            var p = new Person("ZhangSan");
            console.log(p.constructor === Object);  // true
            console.log(Person.prototype.constructor === Object); // true
            console.log(p.constructor.prototype.constructor === Object); // true
            
    怎么修正這種問題呢?方法也很簡單,重新覆蓋Person.prototype.constructor即可:
            function Person(name) {
                this.name = name;
            };
            Person.prototype = new Object({
                getName: function() {
                    return this.name;
                }
            });
            Person.prototype.constructor = Person;
            var p = new Person("ZhangSan");
            console.log(p.constructor === Person);  // true
            console.log(Person.prototype.constructor === Person); // true
            console.log(p.constructor.prototype.constructor === Person); // true
            

    ?


    下一章我們將會對第一章提到的Person-Employee類和繼承的實現進行完善。

    主站蜘蛛池模板: a毛片免费在线观看| 大学生美女毛片免费视频| 日本高清免费观看| AV片在线观看免费| 亚洲最大AV网站在线观看| 国产成人亚洲精品| 一个人看的www免费视频在线观看| 一区二区无码免费视频网站| 亚洲色偷偷偷鲁综合| 亚洲jizzjizz少妇| 久久午夜夜伦鲁鲁片免费无码影视| 国产一级一片免费播放| 亚洲精品成人网站在线播放 | 亚洲欧洲视频在线观看| 91短视频免费在线观看| 亚洲中文字幕无码久久精品1| 久久成人18免费网站| 免费国产成人午夜私人影视 | 天堂亚洲国产中文在线| 无码日韩精品一区二区三区免费| 免费一级肉体全黄毛片| 国产精品青草视频免费播放| 国产精品免费看久久久久| 亚洲手机中文字幕| 日本一区二区免费看| 亚洲国产精品午夜电影| 日本一线a视频免费观看| 国产精品亚洲综合久久| 国产jizzjizz免费视频| 两个人看的www高清免费视频| 91在线亚洲精品专区| 久久久精品2019免费观看| 久久亚洲伊人中字综合精品| 国产黄色片免费看| 久久久久亚洲精品日久生情 | 亚洲成在人线在线播放无码| 亚洲午夜爱爱香蕉片| 九九久久精品国产免费看小说| 又大又黄又粗又爽的免费视频 | 91在线老王精品免费播放| 亚洲欧美中文日韩视频|