站長資訊網
        最全最豐富的資訊網站

        爆肝整理JavaScript之面向對象(總結分享)

        本篇文章給大家帶來了關于JavaScript中面向對象的相關知識,其中包括面向對象、構造函數以及繼承的相關問題,希望對大家有幫助。

        爆肝整理JavaScript之面向對象(總結分享)

        1、面向對象

        面向對象更貼近我們的實際生活, 可以使用面向對象描述現實世界事物. 但是事物分為具體的事物和抽象的事物

        面向對象的思維特點:

        1. 抽取(抽象)對象共用的屬性和行為組織(封裝)成一個類(模板)
        2. 對類進行實例化, 獲取類的對象

        1.1、對象

        在 JavaScript 中,對象是一組無序的相關屬性和方法的集合,所有的事物都是對象,例如字符串、數值、數組、函數等。

        對象是由屬性方法組成的

        • 屬性:事物的特征,在對象中用屬性來表示
        • 方法:事物的行為,在對象中用方法來表示

        1.2、類

        在 ES6 中新增加了類的概念,可以使用 class 關鍵字聲明一個類,之后以這個類來實例化對象。

        • 抽象了對象的公共部分,它泛指某一大類(class)
        • 對象特指某一個,通過類實例化一個具體的對象

        1.2.1、創建類

        class name {     // class body}
        • 創建實例
        var XX = new name();

        注意:類必須使用new 實例化對象

        1.2.2、構造函數

        constructor()方法是類的構造函數(默認方法),用于傳遞參數,返回實例對象,通過 new 命令生成對象實例時,自動調用該方法。如果沒有顯示定義, 類內部會自動給我們創建一個constructor()

        <script>     // 1. 創建類 class  創建一個 明星類     class Star {         // constructor 構造器或者構造函數         constructor(uname, age) {             this.uname = uname;             this.age = age;         }     }      // 2. 利用類創建對象 new     var ldh = new Star('劉德華', 18);     var zxy = new Star('張學友', 20);     console.log(ldh);     console.log(zxy);</script>
        • 通過 class 關鍵字創建類,類名我們還是習慣性定義首字母大寫
        • 類里面有個 constructor函數,可以接收傳遞過來的參數,同時返回實例對象
        • constructor函數只要 new 生成實例時,就會自動調用這個函數,如果我們不寫這個函數,類也會自動生成這個函數
        • 最后注意語法規范
          • 創建類➡類名后面不要加小括號
          • 生成實例➡類名后面加小括號
          • 構造函數不需要加 function 關鍵字

        1.2.3、類中添加方法

        語法:

        class Person {   constructor(name,age) {          // constructor 稱為構造器或者構造函數       this.name = name;       this.age = age;     }    say() {       console.log(this.name + '你好');    }}      var ldh = new Person('劉德華', 18); ldh.say()

        注意: 方法之間不能加逗號分隔,同時方法不需要添加 function 關鍵字。

        <script>     // 1. 創建類 class  創建一個 明星類     class Star {         // 類的共有屬性放到 constructor 里面         constructor(uname, age) {             this.uname = uname;             this.age = age;         }         sing(song) {             console.log(this.uname + song);         }     }      // 2. 利用類創建對象 new     var ldh = new Star('劉德華', 18);     var zxy = new Star('張學友', 20);     console.log(ldh);     console.log(zxy);     // (1) 我們類里面所有的函數不需要寫function      // (2) 多個函數方法之間不需要添加逗號分隔     ldh.sing('冰雨');     zxy.sing('李香蘭');</script>
        • 類的共有屬性放到constructor 里面
        • 類里面的函數都不需要寫 function 關鍵字

        1.3 、類的繼承

        現實中的繼承:子承父業,比如我們都繼承了父親的姓。

        程序中的繼承:子類可以繼承父類的一些屬性和方法。

        語法:

        // 父類class Father {     }// 子類繼承父類class Son extends Father {     }

        看一個實例:

        <script>     // 父類有加法方法     class Father {         constructor(x, y) {             this.x = x;             this.y = y;         }         sum() {             console.log(this.x + this.y);         }     }     // 子類繼承父類加法方法 同時 擴展減法方法     class Son extends Father {         constructor(x, y) {             // 利用super 調用父類的構造函數             // super 必須在子類this之前調用             super(x, y);             this.x = x;             this.y = y;         }         subtract() {             console.log(this.x - this.y);         }     }     var son = new Son(5, 3);     son.subtract();     son.sum();</script>

        1.4、super關鍵字

        • super 關鍵字用于訪問和調用對象父類上的函數,可以調用父類的構造函數,也可以調用父類的普通函數

        1.4.1、調用父類的構造函數

        語法:

        // 父類class Person {     constructor(surname){         this.surname = surname;     }}// 子類繼承父類class Student entends Person {     constructor(surname,firstname) {         super(surname);					//調用父類的 constructor(surname)         this.firstname = firstname;		//定義子類獨有的屬性     }}

        注意:子類在構造函數中使用super,必須放到this前面(必須先調用父類的構造方法,在使用子類構造方法)

        案例:

        // 父類class Father {     constructor(surname){         this.surname = surname;     }     saySurname() {         console.log('我的姓是' + this.surname);     }}// 子類繼承父類class Son entends Father {     constructor(surname,firstname) {         super(surname);					//調用父類的 constructor(surname)         this.firstname = firstname;		//定義子類獨有的屬性     }     sayFirstname() {         console.log('我的名字是:' + this.firstname);     }}var damao = new Son('劉','德華');damao.saySurname();damao.sayFirstname();

        1.4.2、調用父類的普通函數

        語法:

        class Father {     say() {         return '我是爸爸';     }}class Son extends Father {     say(){         // super.say() super調用父類的方法         return super.say() + '的兒子';     }}var damao = new Son();console.log(damao.say());
        • 多個方法之間不需要添加逗號分隔

        • 繼承中屬性和方法的查找原則:就近原則,先看子類,再看父類

        1.4、三個注意點

        1. 在ES6中類沒有變量提升,所以必須先定義類,才能通過類實例化對象
        2. 類里面的共有屬性和方法一定要加 this使用
        3. 類里面的this指向:
          • constructor 里面的 this指向實例對象
          • 方法里面的this指向這個方法的調用者
        <body>     <button>點擊</button>     <script>         var that;         var _that;         class Star {             constructor(uname, age) {                 // constructor 里面的this 指向的是 創建的實例對象                 that = this;                 this.uname = uname;                 this.age = age;                 // this.sing();                 this.btn = document.querySelector('button');                 this.btn.onclick = this.sing;             }             sing() {             // 這個sing方法里面的this 指向的是 btn 這個按鈕,因為這個按鈕調用了這個函數                 console.log(that.uname);                  // that里面存儲的是constructor里面的this             }             dance() {                 // 這個dance里面的this 指向的是實例對象 ldh 因為ldh 調用了這個函數                 _that = this;                 console.log(this);             }         }         var ldh = new Star('劉德華');         console.log(that === ldh);         ldh.dance();         console.log(_that === ldh);          // 1. 在 ES6 中類沒有變量提升,所以必須先定義類,才能通過類實例化對象          // 2. 類里面的共有的屬性和方法一定要加this使用.     </script></body>

        2、構造函數和原型

        2.1、概述

        在典型的 OOP 的語言中(如 Java),都存在類的概念,類就是對象的模板,對象就是類的實例,但在 ES6之前, JS 中并沒用引入類的概念。

        ES6, 全稱 ECMAScript 6.0 ,2015.06 發版。但是目前瀏覽器的 JavaScript 是 ES5 版本,大多數高版本的瀏覽器也支持 ES6,不過只實現了 ES6 的部分特性和功能。

        在 ES6之前 ,對象不是基于類創建的,而是用一種稱為構建函數的特殊函數來定義對象和它們的特征。

        • 創建對象有三種方式
          • 對象字面量
          • new Object()
          • 自定義構造函數
        // 1. 利用 new Object() 創建對象var obj1 = new Object();// 2. 利用對象字面量創建對象var obj2 = {};// 3.利用構造函數創建對象function Star(uname,age) {     this.uname = uname;     this.age = age;     this.sing = function() {         console.log('我會唱歌');     }}var ldh = new Star('劉德華',18);

        注意:

        1. 構造函數用于創建某一類對象,其首字母要大寫
        2. 構造函數要和new一起使用才有意義

        2.2、構造函數

        • 構造函數是一種特殊的函數,主要用來初始化對象(為對象成員變量賦初始值),它總與new一起使用
        • 我們可以把對象中的一些公共的屬性和方法抽取出來,然后封裝到這個函數里面

        new 在執行時會做四件事

        1. 在內存中創建一個新的空對象。
        2. 讓 this 指向這個新的對象。
        3. 執行構造函數里面的代碼,給這個新對象添加屬性和方法。
        4. 返回這個新對象(所以構造函數里面不需要 return )。

        2.2.1、靜態成員和實例成員

        JavaScript 的構造函數中可以添加一些成員,可以在構造函數本身上添加,也可以在構造函數內部的this上添加。通過這兩種方式添加的成員,就分別稱為靜態成員實例成員

        • 靜態成員:在構造函數本身上添加的成員為靜態成員,只能由構造函數本身來訪問
        • 實例成員:在構造函數內部創建的對象成員稱為實例成員,只能由實例化的對象來訪問
        // 構造函數中的屬性和方法我們稱為成員,成員可以添加 function Star(uname,age) {     this.uname = uname;     this.age = age;     this.sing = function() {         console.log('我會唱歌');     } } var ldh = new Star('劉德華',18);  // 實例成員就是構造函數內部通過this添加的成員  uname age sing  就是實例成員 // 實例成員只能通過實例化的對象來訪問 ldh.sing(); Star.uname; // undefined     不可以通過構造函數來訪問實例成員  // 靜態成員就是在構造函數本身上添加的成員 sex 就是靜態成員 // 靜態成員只能通過構造函數來訪問 Star.sex = '男'; Star.sex; ldh.sex; // undefined  不能通過對象來訪問

        2.2.2、構造函數的問題

        構造函數方法很好用,但是存在浪費內存的問題

        爆肝整理JavaScript之面向對象(總結分享)

        • 我們希望所有的對象使用同一個函數,這樣就比較節省內存

        2.3、構造函數原型 prototype

        • 構造函數通過原型分配的函數是所有對象所共享的,這樣就解決了內存浪費問題
        • JavaScript 規定,每一個構造函數都有一個prototype屬性,指向另一個對象,注意這個prototype就是一個對象,這個對象的所有屬性和方法,都會被構造函數所擁有
        • 我們可以把那些不變的方法,直接定義在prototype 對象上,這樣所有對象的實例就可以共享這些方法
        <body>     <script>         // 1. 構造函數的問題.          function Star(uname, age) {     		//公共屬性定義到構造函數里面             this.uname = uname;             this.age = age;             // this.sing = function() {             //     console.log('我會唱歌');             // }         } 		//公共的方法我們放到原型對象身上         Star.prototype.sing = function() {             console.log('我會唱歌');         }         var ldh = new Star('劉德華', 18);         var zxy = new Star('張學友', 19);         console.log(ldh.sing === zxy.sing);         ldh.sing();         zxy.sing();         // 2. 一般情況下,我們的公共屬性定義到構造函數里面, 公共的方法我們放到原型對象身上     </script></body>
        • 一般情況下,我們的公共屬性定義到構造函數里面, 公共的方法我們放到原型對象身上

        問答:原型是什么?

        • 一個對象,我們也稱為 prototype原型對象

        問答:原型的作用是什么?

        • 共享方法

        2.4、對象原型 __ proto __

        • 對象都會有一個屬性 _proto_ 指向構造函數的prototype原型對象,之所以我們對象可以使用構造函數prototype 原型對象的屬性和方法,就是因為對象有_proto_原型的存在。
        • _proto_對象原型和原型對象 prototype 是等價的
        • _proto_對象原型的意義就在于為對象的查找機制提供一個方向,或者說一條路線,但是它是一個非標準屬性,因此實際開發中,不可以使用這個屬性,它只是內部指向原型對象 prototype

        爆肝整理JavaScript之面向對象(總結分享)

        • Star.prototype 和 ldh._proto_ 指向相同
        <body>     <script>         function Star(uname, age) {             this.uname = uname;             this.age = age;         }         Star.prototype.sing = function() {             console.log('我會唱歌');         }         var ldh = new Star('劉德華', 18);         var zxy = new Star('張學友', 19);         ldh.sing();         console.log(ldh);  		// 對象身上系統自己添加一個 __proto__ 指向我們構造函數的原型對象 prototype         console.log(ldh.__proto__ === Star.prototype);         // 方法的查找規則: 首先先看ldh 對象身上是否有 sing 方法,如果有就執行這個對象上的sing         // 如果沒有sing 這個方法,因為有 __proto__ 的存在,就去構造函數原型對象prototype身上去查找sing這個方法     </script></body>

        2.5、constructor 構造函數

        • 對象原型(__ proto __)構造函數(prototype)原型對象里面都有一個屬性constructor屬性, constructor 我們稱為構造函數,因為它指回構造函數本身。

        • constructor主要用于記錄該對象引用于哪個構造函數,它可以讓原型對象重新指向原來的構造函數

        • 一般情況下,對象的方法都在構造函數(prototype)的原型對象中設置

        • 如果有多個對象的方法,我們可以給原型對象prototype采取對象形式賦值,但是這樣會覆蓋構造函數原型對象原來的內容,這樣修改后的原型對象constructor就不再指向當前構造函數了。此時,我們可以在修改后的原型對象中,添加一個constructor指向原來的構造函數

        具體請看實例配合理解

        <body>     <script>         function Star(uname, age) {             this.uname = uname;             this.age = age;         }         // 很多情況下,我們需要手動的利用constructor 這個屬性指回 原來的構造函數         // Star.prototype.sing = function() {         //     console.log('我會唱歌');         // };         // Star.prototype.movie = function() {         //     console.log('我會演電影');         // }         Star.prototype = {             // 如果我們修改了原來的原型對象,給原型對象賦值的是一個對象,則必須手動的利用constructor指回原來的構造函數             constructor: Star,             sing: function() {                 console.log('我會唱歌');             },             movie: function() {                 console.log('我會演電影');             }         }         var ldh = new Star('劉德華', 18);         var zxy = new Star('張學友', 19);     </script></body>

        2.6、構造函數、實例、原型對象三者關系

        爆肝整理JavaScript之面向對象(總結分享)

        2.7、原型鏈查找規則

        1. 當訪問一個對象的屬性(包括方法)時,首先查找這個對象自身有沒有該屬性
        2. 如果沒有就查找它的原型(也就是_proto_指向的prototype原型對象)
        3. 如果還沒有就查找原型對象的原型(Object的原型對象)
        4. 依次類推一直找到Object為止(null)
        5. __ proto __對象原型的意義就在于為對象成員查找機制提供一個方向,或者說一條路線。

        爆肝整理JavaScript之面向對象(總結分享)

        <body>     <script>         function Star(uname, age) {             this.uname = uname;             this.age = age;         }         Star.prototype.sing = function() {             console.log('我會唱歌');         }         var ldh = new Star('劉德華', 18);         // 1. 只要是對象就有__proto__ 原型, 指向原型對象         console.log(Star.prototype);         console.log(Star.prototype.__proto__ === Object.prototype);         // 2.我們Star原型對象里面的__proto__原型指向的是 Object.prototype         console.log(Object.prototype.__proto__);         // 3. 我們Object.prototype原型對象里面的__proto__原型  指向為 null     </script></body>

        2.8、原型對象this指向

        • 構造函數中的 this指向我們的實例對象
        • 原型對象里面放的是方法,這個方法里面的this指向的是這個方法的調用者,也就是這個實例對象
        <body>     <script>         function Star(uname, age) {             this.uname = uname;             this.age = age;         }         var that;         Star.prototype.sing = function() {             console.log('我會唱歌');             that = this;         }         var ldh = new Star('劉德華', 18);         // 1. 在構造函數中,里面this指向的是對象實例 ldh         ldh.sing();         console.log(that === ldh);          // 2.原型對象函數里面的this 指向的是 實例對象 ldh     </script></body>

        2.9、擴展內置對象

        • 可以通過原型對象,對原來的內置對象進行擴展自定義的方法
        • 比如給數組增加自定義求偶數和的功能
        <body>     <script>         // 原型對象的應用 擴展內置對象方法          Array.prototype.sum = function() {             var sum = 0;             for (var i = 0; i < this.length; i++) {                 sum += this[i];             }             return sum;         };         // Array.prototype = {         //     sum: function() {         //         var sum = 0;         //         for (var i = 0; i < this.length; i++) {         //             sum += this[i];         //         }         //         return sum;         //     }          // }         var arr = [1, 2, 3];         console.log(arr.sum());         console.log(Array.prototype);         var arr1 = new Array(11, 22, 33);         console.log(arr1.sum());     </script></body>

        注意:

        • 數組和字符串內置對象不能給原型對象覆蓋操作Array.prototype = {},只能是Array.prototype.xxx = function(){}的方式

        3、繼承

        ES6 之前并沒有給我們提供extends繼承

        • 我們可以通過構造函數+原型對象模擬實現繼承,被稱為組合繼承

        3.1、call()

        調用這個函數,并且修改函數運行時的 this 指向

        fun.call(thisArg,arg1,arg2,......)
        • thisArg:當前調用函數 this 的指向對象
        • arg1,arg2: 傳遞的其他參數

        示例

        <body>     <script>         // call 方法         function fn(x, y) {             console.log('我希望我的希望有希望');             console.log(this);		// Object{...}             console.log(x + y);		// 3         }          var o = {             name: 'andy'         };         // fn();         // 1. call() 可以調用函數         // fn.call();         // 2. call() 可以改變這個函數的this指向 此時這個函數的this 就指向了o這個對象         fn.call(o, 1, 2);     </script></body>

        3.2、借用構造函數繼承父類型屬性

        • 核心原理: 通過 call() 把父類型的 this 指向子類型的 this,這樣就可以實現子類型繼承父類型的屬性
        <body>     <script>         // 借用父構造函數繼承屬性         // 1. 父構造函數         function Father(uname, age) {             // this 指向父構造函數的對象實例             this.uname = uname;             this.age = age;         }         // 2 .子構造函數          function Son(uname, age, score) {             // this 指向子構造函數的對象實例             Father.call(this, uname, age);             this.score = score;         }         var son = new Son('劉德華', 18, 100);         console.log(son);     </script></body>

        3.3、借用原型對象繼承父類型方法

        • 一般情況下,對象的方法都在構造函數的原型對象中設置,通過構造函數無法繼承父類方法

        核心原理:

        1. 將子類所共享的方法提取出來,讓子類的 prototype 原型對象 = new 父類()
        2. 本質: 子類原型對象等于是實例化父類,因為父類實例化之后另外開辟空間,就不會影響原來父類原型對象
        3. 將子類的constructor重新指向子類的構造函數
        <body>     <script>         // 借用父構造函數繼承屬性         // 1. 父構造函數         function Father(uname, age) {             // this 指向父構造函數的對象實例             this.uname = uname;             this.age = age;         }         Father.prototype.money = function() {             console.log(100000);          };         // 2 .子構造函數          function Son(uname, age, score) {             // this 指向子構造函數的對象實例             Father.call(this, uname, age);             this.score = score;         }         // Son.prototype = Father.prototype;  這樣直接賦值會有問題,如果修改了子原型對象,父原型對象也會跟著一起變化         Son.prototype = new Father();         // 如果利用對象的形式修改了原型對象,別忘了利用constructor 指回原來的構造函數         Son.prototype.constructor = Son;         // 這個是子構造函數專門的方法         Son.prototype.exam = function() {             console.log('孩子要考試');          }         var son = new Son('劉德華', 18, 100);         console.log(son);         console.log(Father.prototype);         console.log(Son.prototype.constructor);     </script></body>

        3.3 類的本質

        1. class 本質還是 function
        2. 類的所有方法都定義在類的 prototype屬性上
        3. 類創建的實例,里面也有_proto_指向類的prototype原型對象
        4. 所以 ES6 的類它的絕大部分功能,ES5都可以做到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。
        5. 所以 ES6 的類其實就是語法糖
        6. 語法糖:語法糖就是一種便捷寫法,簡單理解

        4、ES5新增方法

        ES5 給我們新增了一些方法,可以很方便的操作數組或者字符串

        • 數組方法
        • 字符串方法
        • 對象方法

        4.1、數組方法

        • 迭代(遍歷)方法:foreach() ,map(),filter(),some() ,every() ;

        4.1.1、forEach()

        array.forEach(function(currentValue,index,arr))
        • currentValue: 數組當前項的值
        • index: 數組當前項的索引
        • arr: 數組對象本身
        <body>     <script>         // forEach 迭代(遍歷) 數組         var arr = [1, 2, 3];         var sum = 0;         arr.forEach(function(value, index, array) {             console.log('每個數組元素' + value);             console.log('每個數組元素的索引號' + index);             console.log('數組本身' + array);             sum += value;         })         console.log(sum);     </script></body>

        4.1.2、filter()篩選數組

        array.filter(function(currentValue,index,arr))
        • filter()方法創建一個新的數組,新數組中的元素是通過檢查指定數組中符合條件的所有元素,主要用于篩選數組
        • 注意它直接返回一個新數組
        <body>     <script>         // filter 篩選數組         var arr = [12, 66, 4, 88, 3, 7];         var newArr = arr.filter(function(value, index) {             // return value >= 20;             return value % 2 === 0;         });         console.log(newArr);     </script></body>

        4.1.3、some()

        • some()方法用于檢測數組中的元素是否滿足指定條件(查找數組中是否有滿足條件的元素)
        • 注意它返回的是布爾值,如果查找到這個元素,就返回true,如果查找不到就返回false
        • 如果找到第一個滿足條件的元素,則終止循環,不再繼續查找
        <body>     <script>         // some 查找數組中是否有滿足條件的元素          var arr1 = ['red', 'pink', 'blue'];         var flag1 = arr1.some(function(value) {             return value == 'pink';         });         console.log(flag1);         // 1. filter 也是查找滿足條件的元素 返回的是一個數組 而且是把所有滿足條件的元素返回回來         // 2. some 也是查找滿足條件的元素是否存在  返回的是一個布爾值 如果查找到第一個滿足條件的元素就終止循環     </script></body>

        4.2、字符串方法

        • trim()方法會從一個字符串的兩端刪除空白字符
        • trim()方法并不影響原字符串本身,它返回的是一個新的字符串
        <body>     <input type="text"> <button>點擊</button>     <p></p>     <script>         // trim 方法去除字符串兩側空格         var str = '   an  dy   ';         console.log(str);         var str1 = str.trim();         console.log(str1);         var input = document.querySelector('input');         var btn = document.querySelector('button');         var p = document.querySelector('p');         btn.onclick = function() {             var str = input.value.trim();             if (str === '') {                 alert('請輸入內容');             } else {                 console.log(str);                 console.log(str.length);                 p.innerHTML = str;             }         }     </script></body>

        4.3、對象方法

        4.3.1、Object.keys()

        1. Object.keys()用于獲取對象自身所有的屬性
        2. 效果類似for...in
        3. 返回一個由屬性名組成的數組
        <body>     <script>         // 用于獲取對象自身所有的屬性         var obj = {             id: 1,             pname: '小米',             price: 1999,             num: 2000         };         var arr = Object.keys(obj);         console.log(arr);         arr.forEach(function(value) {             console.log(value);             // id             // pname             // price             // num         })     </script></body>

        4.3.2、Object.defineProperty()

        • Object.defineProperty()定義對象中新屬性或修改原有的屬性(了解)
        Object.defineProperty(obj,prop,descriptor)
        • obj : 目標對象
        • prop : 需定義或修改的屬性的名字
        • descriptor : 目標屬性所擁有的特性
        <body>     <script>         // Object.defineProperty() 定義新屬性或修改原有的屬性         var obj = {             id: 1,             pname: '小米',             price: 1999         };         // 1. 以前的對象添加和修改屬性的方式         // obj.num = 1000;         // obj.price = 99;         // console.log(obj);         // 2. Object.defineProperty() 定義新屬性或修改原有的屬性         Object.defineProperty(obj, 'num', {             value: 1000,             enumerable: true         });         console.log(obj);         Object.defineProperty(obj, 'price', {             value: 9.9         });         console.log(obj);         Object.defineProperty(obj, 'id', {             // 如果值為false 不允許修改這個屬性值 默認值也是false             writable: false,         });         obj.id = 2;         console.log(obj);         Object.defineProperty(obj, 'address', {             value: '中國山東藍翔技校xx單元',             // 如果只為false 不允許修改這個屬性值 默認值也是false             writable: false,             // enumerable 如果值為false 則不允許遍歷, 默認的值是 false             enumerable: false,             // configurable 如果為false 則不允許刪除這個屬性 不允許在修改第三個參數里面的特性 默認為false             configurable: false         });         console.log(obj);         console.log(Object.keys(obj));         delete obj.address;         console.log(obj);         delete obj.pname;         console.log(obj);         Object.defineProperty(obj, 'address', {             value: '中國山東藍翔技校xx單元',             // 如果值為false 不允許修改這個屬性值 默認值也是false             writable: true,             // enumerable 如果值為false 則不允許遍歷, 默認的值是 false             enumerable: true,             // configurable 如果為false 則不允許刪除這個屬性 默認為false             configurable: true         });         console.log(obj.address);     </script></body>
        • 第三個參數 descriptor 說明:以對象形式{ }書寫
        • value:設置屬性的值,默認為undefined
        • writeable: 值是否可以重寫 true | false 默認為false
        • enumerable: 目標屬性是否可以被枚舉 true | false 默認為false
        • configurable: 目標屬性是否可以被刪除或是否可以再次修改特性 true | false 默認為false

        5、函數進階

        5.1、函數的定義方式

        1. 函數聲明方式 function 關鍵字(命名函數)
        2. 函數表達式(匿名函數)
        3. new Function()
        var fn = new Function('參數1','參數2',.....,'函數體');
        • Function 里面參數都必須是字符串格式

        • 第三種方式執行效率低,也不方便書寫,因此較少使用

        • 所有函數都是 Function 的實例(對象)

        • 函數也屬于對象

        爆肝整理JavaScript之面向對象(總結分享)

        <body>     <script>         //  函數的定義方式          // 1. 自定義函數(命名函數)           function fn() {};          // 2. 函數表達式 (匿名函數)          var fun = function() {};           // 3. 利用 new Function('參數1','參數2', '函數體'); 		//             Function 里面參數都必須是字符串格式,執行效率低,較少寫          var f = new Function('a', 'b', 'console.log(a + b)');         f(1, 2);         // 4. 所有函數都是 Function 的實例(對象)         console.dir(f);         // 5. 函數也屬于對象         console.log(f instanceof Object);     </script></body>

        5.2、函數的調用方式

        1. 普通函數
        2. 對象的方法
        3. 構造函數
        4. 綁定事件函數
        5. 定時器函數
        6. 立即執行函數
        <body>     <script>         // 函數的調用方式          // 1. 普通函數         function fn() {             console.log('人生的巔峰');          }         // fn();   fn.call()         // 2. 對象的方法         var o = {             sayHi: function() {                 console.log('人生的巔峰');              }         }         o.sayHi();         // 3. 構造函數         function Star() {};         new Star();         // 4. 綁定事件函數         // btn.onclick = function() {};   // 點擊了按鈕就可以調用這個函數         // 5. 定時器函數         // setInterval(function() {}, 1000);  這個函數是定時器自動1秒鐘調用一次         // 6. 立即執行函數         (function() {             console.log('人生的巔峰');         })();         // 立即執行函數是自動調用     </script></body>

        5.3、函數內this的指向

        • this指向,是當我們調用函數的時候確定的,調用方式的不同決定了this的指向不同,一般我們指向我們的調用者
        調用方式 this指向
        普通函數調用 window
        構造函數調用 實例對象,原型對象里面的方法也指向實例對象
        對象方法調用 該方法所屬對象
        事件綁定方法 綁定事件對象
        定時器函數 window
        立即執行函數 window
        <body>     <button>點擊</button>     <script>         // 函數的不同調用方式決定了this 的指向不同         // 1. 普通函數 this 指向window         function fn() {             console.log('普通函數的this' + this);         }         window.fn();         // 2. 對象的方法 this指向的是對象 o         var o = {             sayHi: function() {                 console.log('對象方法的this:' + this);             }         }         o.sayHi();         // 3. 構造函數 this 指向 ldh 這個實例對象 原型對象里面的this 指向的也是 ldh這個實例對象         function Star() {};         Star.prototype.sing = function() {          }         var ldh = new Star();         // 4. 綁定事件函數 this 指向的是函數的調用者 btn這個按鈕對象         var btn = document.querySelector('button');         btn.onclick = function() {             console.log('綁定時間函數的this:' + this);         };         // 5. 定時器函數 this 指向的也是window         window.setTimeout(function() {             console.log('定時器的this:' + this);          }, 1000);         // 6. 立即執行函數 this還是指向window         (function() {             console.log('立即執行函數的this' + this);         })();     </script></body>

        5.4、改變函數內部this指向

        • JavaScript 為我們專門提供了一些函數方法來幫我們處理函數內部 this 的指向問題,常用的有 bind(),call(),apply()三種方法

        5.4.1、call() 方法

        • call()方法調用一個對象,簡單理解為調用函數的方式,但是它可以改變函數的this指向
        • fun.call(thisArg,arg1,arg2,.....)
        • thisArg: 在 fun 函數運行時指定的 this 值
        • arg1,arg2: 傳遞的其他參數
        • 返回值就是函數的返回值,因為它就是調用函數
        • 因此當我們想改變 this 指向,同時想調用這個函數的時候,可以使用 call,比如繼承
        <body>     <script>         // 改變函數內this指向  js提供了三種方法  call()  apply()  bind()          // 1. call()         var o = {             name: 'andy'         }          function fn(a, b) {             console.log(this);             console.log(a + b);          };         fn.call(o, 1, 2);         // call 第一個可以調用函數 第二個可以改變函數內的this 指向         // call 的主要作用可以實現繼承         function Father(uname, age, sex) {             this.uname = uname;             this.age = age;             this.sex = sex;         }          function Son(uname, age, sex) {             Father.call(this, uname, age, sex);         }         var son = new Son('劉德華', 18, '男');         console.log(son);     </script></body>

        5.4.2、apply()方法

        • apply()方法調用一個函數,簡單理解為調用函數的方式,但是它可以改變函數的 this指向
        • fun.apply(thisArg,[argsArray])
        • thisArg: 在 fun 函數運行時指定的 this 值
        • argsArray : 傳遞的值,必須包含在數組里面
        • 返回值就是函數的返回值,因為它就是調用函數
        • 因此 apply 主要跟數組有關系,比如使用 Math.max() 求數組的最大值
        <body>     <script>         // 改變函數內this指向  js提供了三種方法  call()  apply()  bind()          // 2. apply()  應用 運用的意思         var o = {             name: 'andy'         };          function fn(arr) {             console.log(this);             console.log(arr); // 'pink'          };         fn.apply(o, ['pink']);         // 1. 也是調用函數 第二個可以改變函數內部的this指向         // 2. 但是他的參數必須是數組(偽數組)         // 3. apply 的主要應用 比如說我們可以利用 apply 借助于數學內置對象求數組最大值          // Math.max();         var arr = [1, 66, 3, 99, 4];         var arr1 = ['red', 'pink'];         // var max = Math.max.apply(null, arr);         var max = Math.max.apply(Math, arr);         var min = Math.min.apply(Math, arr);         console.log(max, min);     </script></body>

        5.4.3、bind()方法

        • bind()方法不會調用函數。但是能改變函數內部 this指向
        • fun.bind(thisArg,arg1,arg2,....)
        • 返回由指定的 this值和初始化參數改造的原函數拷貝
        • 因此當我們只是想改變 this 指向,并且不想調用這個函數的時候,可以使用bind
        <body>     <button>點擊</button>     <button>點擊</button>     <button>點擊</button>     <script>         // 改變函數內this指向  js提供了三種方法  call()  apply()  bind()          // 3. bind()  綁定 捆綁的意思         var o = {             name: 'andy'         };          function fn(a, b) {             console.log(this);             console.log(a + b);           };         var f = fn.bind(o, 1, 2);         f();         // 1. 不會調用原來的函數   可以改變原來函數內部的this 指向         // 2. 返回的是原函數改變this之后產生的新函數         // 3. 如果有的函數我們不需要立即調用,但是又想改變這個函數內部的this指向此時用bind         // 4. 我們有一個按鈕,當我們點擊了之后,就禁用這個按鈕,3秒鐘之后開啟這個按鈕         // var btn1 = document.querySelector('button');         // btn1.onclick = function() {         //     this.disabled = true; // 這個this 指向的是 btn 這個按鈕         //     // var that = this;         //     setTimeout(function() {         //         // that.disabled = false; // 定時器函數里面的this 指向的是window         //         this.disabled = false; // 此時定時器函數里面的this 指向的是btn         //     }.bind(this), 3000); // 這個this 指向的是btn 這個對象         // }         var btns = document.querySelectorAll('button');         for (var i = 0; i < btns.length; i++) {             btns[i].onclick = function() {                 this.disabled = true;                 setTimeout(function() {                     this.disabled = false;                 }.bind(this), 2000);             }         }     </script></body>

        5.4.4、總結

        call apply bind 總結:

        相同點:

        • 都可以改變函數內部的 this指向

        區別點:

        • callapply會調用函數,并且改變函數內部的this指向
        • callapply傳遞的參數不一樣,call 傳遞參數,apply 必須數組形式
        • bind不會調用函數,可以改變函數內部this指向

        主要應用場景

        1. call經常做繼承
        2. apply經常跟數組有關系,比如借助于數學對線實現數組最大值與最小值
        3. bind不調用函數,但是還想改變this指向,比如改變定時器內部的this指向

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 少妇人妻无码精品视频| 91麻豆精品国产自产在线观看一区 | 网友偷拍日韩精品| 国产色婷婷五月精品综合在线 | 国产日韩欧美精品| 久久久精品久久久久久| 亚洲精品乱码久久久久久中文字幕| 国产欧美国产精品第一区| 亚洲精品一级无码中文字幕| 一级香蕉精品视频在线播放| 无码精品国产一区二区三区免费 | 国产精品夜色一区二区三区| 亚洲AV永久无码精品一区二区 | 午夜国产精品无套| 国精品产露脸自拍| 国产成人精品久久亚洲高清不卡| 国产亚洲精品xxx| 成人国产精品999视频| 精品无人区一区二区三区| 在线观看自拍少妇精品| 污污网站国产精品白丝袜| 久久久久亚洲精品无码网址| 精品国产一区二区三区在线观看 | 99久久精品这里只有精品| 久久久精品人妻一区二区三区蜜桃 | 国产69精品久久久久777| 国产精品内射后入合集| 久久成人国产精品| 精品久久久久中文字幕日本| 无码精品一区二区三区在线| 日本一卡精品视频免费| 人妻少妇精品视中文字幕国语| 人妻少妇偷人精品无码| 久久久无码精品亚洲日韩按摩 | 色婷婷久久久SWAG精品| 青青青青久久精品国产h久久精品五福影院1421 | 久久亚洲中文字幕精品一区四| 久久精品国产精品亚洲| 精品综合久久久久久88小说| 蜜臀精品无码AV在线播放| 久久久久人妻精品一区三寸蜜桃|