JavaScript知識:構造函數也是函數
首先要明確的是構造函數也是函數
我經常使用構造函數來創(chuàng)建實例對象,例如對象和數組的實例化可以通過相應的構造函數Object()和Array()完成。
構造函數與普通函數在語法的定義上沒有任何區(qū)別,主要的區(qū)別體現在以下3點。
(1)構造函數的函數名的第一個字母通常會大寫。按照慣例,構造函數名稱的首字母都是要大寫的,非構造函數則以小寫字母開頭。這是從面向對象編程語言那里借鑒的,有助于在ECMAScript中區(qū)分構造函數和普通函數。
(2)在函數體內部使用this關鍵字,表示要生成的對象實例,構造函數并不會顯式地返回任何值,而是默認返回“this”。在下面的代碼段中,Person()函數并沒有使用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.定義構造函數
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)作為構造函數調用時,必須與new操作符配合使用。這一點非常重要,任何函數只要使用new操作符調用就是構造函數,而不使用new操作符調用的函數就是普通函數。
1、構造函數的定義與調用
構造函數又稱為自定義函數,以函數的形式為自己的對象類型定義屬性和方法。
舉例:
<!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.定義構造函數
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關鍵字的用途
構造函數在執(zhí)行時,會執(zhí)行以下4步:
- 通過new關鍵字(操作符)創(chuàng)建實例對象,會在內存中創(chuàng)建一個新的地址。
- 為構造函數中的this確定指向,指向實例的本身。
- 執(zhí)行構造函數代碼,為實例添加屬性。
- 返回這個新創(chuàng)建的對象。
以前面生成person1實例的代碼為例。
第一步:為person1實例在內存中創(chuàng)建一個新的地址。
第二步:確定person1實例的this指向,指向person本身。
第三步:為person1實例添加name、age和sayName屬性,其中sayName屬性值是一個函數。
第四步:返回這個person1實例。
舉個實例
var person1 = new Person("Bob", 18);
這行代碼,等價于
// 演示 new 的功能
function Person(name,age) {
// 1.創(chuàng)建一個新對象
var instance = new Object();
// 2.將函數內部的 this 指向了這個新對象
this = instance;
// 3.執(zhí)行構造函數內部的代碼
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.將函數內部的 this 指向了這個新對象
this = person1;
// 3.執(zhí)行構造函數內部的代碼
this.name = name;
this.age = age;
this.sayName = function () {
console.log(this.name);
};
// 4.將新對象作為返回值
return person1;
}
3、構造函數的問題:浪費內存
基本事實:不同實例中的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.自定義構造函數
function Person(name,age) {
this.name = name;
this.age = age;
// this 內部的 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,判斷各自的方法是否是同一個函數
console.log(person1.sayName === person2.sayName); // false
</script>
</body>
</html>
解釋:通過console.log(person1.sayName === person2.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: 將公共的函數提取到構造函數之外
function sayName() {
console.log(this.name);
}
function sayAge() {
console.log(this.age);
}
//1.自定義對象
function Person(name,age) {
this.name = name;
this.age = age;
// this 內部的 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>
此時,也存在一個問題,如果有多個公共函數,需要在外部創(chuàng)建多個函數,可能會造成命名沖突
解決辦法,將多個公共的函數封裝到一個對象
<!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.將多個公共的函數封裝到一個對象
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>
解釋:將多個函數封裝成一個對象即可解決函數名可能沖突的問題。
通過這種設置全局訪問的函數,這樣就可以被所有實例訪問到,而不用重復創(chuàng)建。
但是這樣也會存在一個問題,如果為一個對象添加的所有函數都處理成全局函數,這樣并無法完成對一個自定義類型對象的屬性封裝(言外之意。指的是全局函數只可以封裝函數,但無法封裝屬性,因為屬性封裝在函數外面,要定義為全局變量,才可以去調用,這反而會污染全局變量),因此這不是一個好的解決辦法。
此時,便引用原型的概念,使用原型概念可以很好解決這個問題,可以很好解決這個問題。
總結
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!
相關文章
一文了解JavaScript用Element?Traversal新屬性遍歷子元素
這篇文章主要介紹了一文了解JavaScript用Element?Traversal新屬性遍歷子元素,文章圍繞Element?Traversal新屬性的相關資料展開詳細內容,需要的朋友可以參考一下,希望對大家有所幫助2021-11-11
three.js-結合dat.gui實現界面可視化修改及調試詳解
這篇文章主要為大家介紹了three.js-結合dat.gui實現界面可視化修改及調試詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02
微信小程序 加載 app-service.js 錯誤解決方法
這篇文章主要介紹了微信小程序 加載 app-service.js 錯誤詳解的相關資料,在開發(fā)微信小程序過程中出現了app-services.js的錯誤,并解決此問題,需要的朋友可以參考下2016-10-10

