JavaScript知識:構造函數(shù)也是函數(shù)
首先要明確的是構造函數(shù)也是函數(shù)
我經(jīng)常使用構造函數(shù)來創(chuàng)建實例對象,例如對象和數(shù)組的實例化可以通過相應的構造函數(shù)Object()和Array()完成。
構造函數(shù)與普通函數(shù)在語法的定義上沒有任何區(qū)別,主要的區(qū)別體現(xiàn)在以下3點。
(1)構造函數(shù)的函數(shù)名的第一個字母通常會大寫。按照慣例,構造函數(shù)名稱的首字母都是要大寫的,非構造函數(shù)則以小寫字母開頭。這是從面向對象編程語言那里借鑒的,有助于在ECMAScript中區(qū)分構造函數(shù)和普通函數(shù)。
(2)在函數(shù)體內(nèi)部使用this關鍵字,表示要生成的對象實例,構造函數(shù)并不會顯式地返回任何值,而是默認返回“this”。在下面的代碼段中,Person()函數(shù)并沒有使用return關鍵字返回任何信息,但是輸出的變量person1是一個具有name、age屬性值的Person實例。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> //1.定義構造函數(shù) function Person(name,age){ this.age = age; this.name = name; this.sayName = function(){ console.log(this.name); } } // 2.生成實例對象 var person1 = new Person('小蘇','18'); // 3.打印實例對象 console.log(person1); </script> </body> </html>
顯示效果如下
(3)作為構造函數(shù)調用時,必須與new操作符配合使用。這一點非常重要,任何函數(shù)只要使用new操作符調用就是構造函數(shù),而不使用new操作符調用的函數(shù)就是普通函數(shù)。
1、構造函數(shù)的定義與調用
構造函數(shù)又稱為自定義函數(shù),以函數(shù)的形式為自己的對象類型定義屬性和方法。
舉例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> //1.定義構造函數(shù) function Person(name,age){ this.age = age; this.name = name; this.sayName = function(){ console.log(this.name); } } // 2.生成實例對象 var person1 = new Person('小蘇','18'); // 3.調用方法 person1.sayName(); </script> </body> </html>
2、new關鍵字的用途
構造函數(shù)在執(zhí)行時,會執(zhí)行以下4步:
- 通過new關鍵字(操作符)創(chuàng)建實例對象,會在內(nèi)存中創(chuàng)建一個新的地址。
- 為構造函數(shù)中的this確定指向,指向實例的本身。
- 執(zhí)行構造函數(shù)代碼,為實例添加屬性。
- 返回這個新創(chuàng)建的對象。
以前面生成person1實例的代碼為例。
第一步:為person1實例在內(nèi)存中創(chuàng)建一個新的地址。
第二步:確定person1實例的this指向,指向person本身。
第三步:為person1實例添加name、age和sayName屬性,其中sayName屬性值是一個函數(shù)。
第四步:返回這個person1實例。
舉個實例
var person1 = new Person("Bob", 18);
這行代碼,等價于
// 演示 new 的功能 function Person(name,age) { // 1.創(chuàng)建一個新對象 var instance = new Object(); // 2.將函數(shù)內(nèi)部的 this 指向了這個新對象 this = instance; // 3.執(zhí)行構造函數(shù)內(nèi)部的代碼 this.name = name; this.age = age; this.sayName = function () { console.log(this.name); }; // 4.將新對象作為返回值 return instance; }
這就意味著,將instance 賦值給 person1,即person1 = instance。實際上又是這樣的:
// 演示 new 的功能 function Person(name,age) { // 1.創(chuàng)建一個新對象 var person1 = new Object(); // 2.將函數(shù)內(nèi)部的 this 指向了這個新對象 this = person1; // 3.執(zhí)行構造函數(shù)內(nèi)部的代碼 this.name = name; this.age = age; this.sayName = function () { console.log(this.name); }; // 4.將新對象作為返回值 return person1; }
3、構造函數(shù)的問題:浪費內(nèi)存
基本事實:不同實例中的sayName屬性是不同的。舉個例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> // 1.自定義構造函數(shù) function Person(name,age) { this.name = name; this.age = age; // this 內(nèi)部的 type 屬性值是不變的 this.type = "human"; // 每個對象的 sayName 方法也是一樣的 this.sayName = function () { console.log(this.name); }; } var person1 = new Person('Bob',18); var person2 = new Person('Mike',20); // 2,判斷各自的方法是否是同一個函數(shù) console.log(person1.sayName === person2.sayName); // false </script> </body> </html>
解釋:通過console.log(person1.sayName === person2.sayName)方法可判斷兩個函數(shù)是否是是同一個,顯然這不是同一個函數(shù),那么兩個函數(shù)就占用了兩個內(nèi)存空間,就會造成內(nèi)存的浪費。
那如何解決函數(shù)占用內(nèi)存的辦法呢?答案是將對象內(nèi)部函數(shù)提取出來作為公共函數(shù)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> // 解決方法1: 將公共的函數(shù)提取到構造函數(shù)之外 function sayName() { console.log(this.name); } function sayAge() { console.log(this.age); } //1.自定義對象 function Person(name,age) { this.name = name; this.age = age; // this 內(nèi)部的 type 屬性值是不變的 this.type = "human"; // 每個對象的 sayName 方法也是一樣的 this.sayName = sayName; this.sayAge = sayAge; } //2.實例化對象 var person1 = new Person('Bob',18); var person2 = new Person('Mike',20); console.log(person1.sayName === person2.sayName); // true </script> </body> </html>
此時,也存在一個問題,如果有多個公共函數(shù),需要在外部創(chuàng)建多個函數(shù),可能會造成命名沖突
解決辦法,將多個公共的函數(shù)封裝到一個對象
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> // 3.將多個公共的函數(shù)封裝到一個對象 var fns = { sayName : function () { console.log(this.name); }, sayAge : function () { console.log(this.age); } }; // 1.自定義對象 function Person(name,age) { this.name = name; this.age = age; this.type = "human"; this.sayName = fns.sayName; this.sayAge = fns.sayAge; } // 2.生成對象實例 var person1 = new Person("Bob",18); var person2 = new Person("Mike",20); // person1.sayName(); console.log(person1.sayName === person2.sayName); console.log(person1.sayAge === person2.sayAge); </script> </body> </html>
解釋:將多個函數(shù)封裝成一個對象即可解決函數(shù)名可能沖突的問題。
通過這種設置全局訪問的函數(shù),這樣就可以被所有實例訪問到,而不用重復創(chuàng)建。
但是這樣也會存在一個問題,如果為一個對象添加的所有函數(shù)都處理成全局函數(shù),這樣并無法完成對一個自定義類型對象的屬性封裝(言外之意。指的是全局函數(shù)只可以封裝函數(shù),但無法封裝屬性,因為屬性封裝在函數(shù)外面,要定義為全局變量,才可以去調用,這反而會污染全局變量),因此這不是一個好的解決辦法。
此時,便引用原型的概念,使用原型概念可以很好解決這個問題,可以很好解決這個問題。
總結
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關注腳本之家的更多內(nèi)容!
相關文章
微信小程序 使用picker封裝省市區(qū)三級聯(lián)動實例代碼
這篇文章主要介紹了微信小程序 使用picker封裝省市區(qū)三級聯(lián)動實例代碼的相關資料,需要的朋友可以參考下2016-10-10