首頁 web前端 js教程 JavaScript之自定义类型_javascript技巧

JavaScript之自定义类型_javascript技巧

May 16, 2016 pm 05:53 PM
自訂類型

1、直接创建模式。这是最简单也是最直接的一种模式,首先创建一个引用类型的对象,然后为其添加自定义属性和方法。示例代码如下:

复制代码 代码如下:

var person = new Object();
person.name = "Sam";
person.age = 16;
person.speak = function(){
alert(this.name + "is " + this.age + "years old");
}
person.speak();

可以看到,上面创建了一个Object类型的对象,然后为其添加了name和age属性以及一个speak方法。直接创建模式虽然简单,但其缺点是显而易见的:当我们需要创建许多相同的对象时,每次都要重复编写代码。为了解决这个问题,我们可以将创建对象的过程进行封装,于是便有了下面的工厂模式。
2、工厂模式。工厂模式是程序设计中一种常用的设计模式,它主要是将创建对象的过程进行了封装,示例代码如下:

复制代码 代码如下:

function createPerson(name, age){
var person = new Object();
person.name = name;
person.age = age;
person.speak = function(){
alert(this.name + "is " + this.age + "years old");
}
return person;
}
var person1 = createPerson("Sam", 16);
var person2 = createPerson("Jack", 18);

使用工厂模式后,创建相同类型的对象变得简单了。但工厂模式没有解决对象识别的问题,即我们无法确定创建的对象的具体类型。有过面向对象编程经验的开发人员都知道,对象的创建应当基于类,有了具体的自定义类,再来创建该类的对象。幸好,在JavaScript中,我们可以通过构造函数模式来模拟一个类。
3、构造函数模式。构造函数和普通函数没有任何区别。任何普通函数都可以作为构造函数,只要使用new操作符即可;任何构造函数也都可以作为普通函数来调用。只不过在JavaScript中,有一个约定,就是用作构造函数的函数名需要首字母大写。示例代码如下:

复制代码 代码如下:

function Person(name, age){
this.name = name;
this.age = age;
this.speak = function(){
alert(this.name + "is " + this.age + "years old");
}
}
var person1 = new Person("Sam", 16);
var person2 = new Person("Jack", 18);

可以看到,在构造函数内部,我们使用了this来添加属性和方法,那么,这个this是指什么呢?当我们创建了一个Person的对象时,this即是指这个创建的对象。现在,我们可以识别出对象person1和person2的具体类型了。使用alert(person1 instanceOf Person)后可以发现,输出的值为true。但构造函数模式也有自己的缺点,就是构造函数内声明的方法在每次创建新对象时都会重新创建(在JavaScript中,函数也是对象)。也就是说,构造函数内的方法是与对象绑定的,而不是与类绑定的。下面代码的输出可以验证我们的推断。
alert(person1.speak == person2.speak); // false 解决这个缺点的一种比较简单的方法就是将函数的声明放到构造函数的外面,即:

复制代码 代码如下:

function Person(name, age){
this.name = name;
this.age = age;
this.speak = speak;
}
function speak(){
alert(this.name + "is " + this.age + "years old");
}
var person1 = new Person("Sam", 16);
var person2 = new Person("Jack", 18);
alert(person1.speak == person2.speak); // true

问题解决了,但这种方法又带来了新的问题。首先,函数speak是在全局作用域中声明的,但它却只能被用于Person构造函数,放在全局作用域中有被误用的风险;其次,如果一个自定义类型有很多的方法,则需要声明很多的全局函数,这既将导致全局作用域的污染,也不利于代码的封装。那么,有没有什么办法能让自定义类型的方法成为与类绑定的,又不污染全局作用域呢?答案是使用原型模式。
4、原型模式。在我们声明一个新的函数后,该函数(在JavaScript中,函数也是对象)就会拥有一个prototype的属性。prototype是一个对象,表示会被该函数创建的所有对象拥有的公共属性和方法。示例代码如下:

复制代码 代码如下:

function Person(){}
Person.prototype.name="Sam";
Person.prototype.age=16;
Person.prototype.speak = function(){
alert(this.name + "is " + this.age + "years old");
}
var person1 = new Person();
person1.speak();
var person2 = new Person();
alert(person1.speak == person2.speak); // true


可以看到,虽然构造函数内没有声明speak方法,但我们创建的对象person1还是能调用speak方法,这是因为JavaScript有一个搜索规则,先搜索实例属性和方法,找到则返回;如果没找到,则再到prototype中去搜索。原型模式使得方法是与类相关的,并且没有污染全局作用域,但其也有自身的缺点:一是所有属性也都与类相关,这意味着所有对象共享一份属性,这显然是不合理的;二是没有办法向构造函数传入初始化数据了。解决的方法很简单,就是混合使用构造函数模式和原型模式。
5、组合模式。示例代码如下:

复制代码 代码如下:

function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.speak = function(){
alert(this.name + "is " + this.age + "years old");
}
var person1 = new Person();
person1.speak();
var person2 = new Person();
alert(person1.speak == person2.speak); // true

不难发现,组合模式实现了我们的所有需求,这也是目前应用得比较广泛的一种模式。有面向对象编程经验的开发人员可能会觉得将prototype的声明放在构造函数外面有点别扭,那么能否将其放到构造函数里去呢?答案是肯定的,使用动态组合模式即可。
6、动态组合模式。其原理就是先判断原型中的某个属性或方法是不是已经声明过,如果没有声明,则声明整个原型;否则,什么也不用做。示例代码如下:

复制代码 代码如下:

function Person(name, age){
this.name = name;
this.age = age;
if (Person.prototype.speak == "undefined"){
Person.prototype.speak = function(){
alert(this.name + "is " + this.age + "years old");
}
}
}
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用 Go 語言定義和使用自訂類型? 如何使用 Go 語言定義和使用自訂類型? Jun 05, 2024 pm 12:41 PM

在Go中,自訂類型可使用type關鍵字定義(struct),包含命名欄位。它們可以透過欄位存取運算子訪問,並可附加方法來操作實例狀態。在實際應用中,自訂類型用於組織複雜資料和簡化操作。例如,學生管理系統使用自訂類型Student儲存學生訊息,並提供計算平均成績和出席率的方法。

C++ 函數在傳回自訂類型時有什麼要求? C++ 函數在傳回自訂類型時有什麼要求? Apr 19, 2024 pm 03:33 PM

C++函數可以傳回自訂類型,滿足以下要求:類型完整定義。預設構造函數。值類型需要複製建構函式。

在 Golang 中,如何比較自訂類型的值? 在 Golang 中,如何比較自訂類型的值? Jun 05, 2024 pm 01:04 PM

在Golang中,可透過以下方式比較自訂類型的值:對於具有相同底層表示形式的類型,直接使用==運算元進行比較。對於更複雜的類型,使用reflect.DeepEqual函數遞歸比較兩個值的全部內容。

如何在 Golang 中建立不可變自訂類型? 如何在 Golang 中建立不可變自訂類型? Jun 02, 2024 am 09:41 AM

是的,在Go中創建不可變的自訂類型可以提供許多好處,包括線程安全性、易於推理和更強的錯誤處理。若要建立不可變類型,需要遵循以下步驟:定義類型:宣告一個包含成員變數的自訂類型,不應包含指標。宣告不可變性:確保所有成員變數都是基礎類型或其他不可變類型,避免使用切片、映射或指標。使用值接收器方法:為與類型關聯的方法使用值接收器,禁止結構體字面量分配,強制方法僅對自身進行操作。

使用 Golang 時如何對自訂類型進行序列化? 使用 Golang 時如何對自訂類型進行序列化? Jun 03, 2024 pm 05:07 PM

在Go中,序列化自訂類型的方法有:使用JSON序列化時實作json.Marshaler接口,使用Gob序列化時實作encoding/gob套件中的GobEncoder和GobDecoder介面。

如何在 Golang 中重載運算子以自訂類型? 如何在 Golang 中重載運算子以自訂類型? Jun 02, 2024 am 09:26 AM

Go中可以透過重載運算子來自訂類型,方法是為類型建立同名方法,接收另一個類型實例並傳回同類型結果。透過這種方式,可以像內建運算符一樣使用自訂運算符,從而方便程式碼的易用性和可讀性。

如何在Go中實作自訂類型? 如何在Go中實作自訂類型? May 10, 2023 pm 03:34 PM

Go是一種物件導向的靜態類型程式語言,因此允許開發者透過自訂類型來簡化程式碼並提高可讀性。在本文中,我們將探討如何在Go中實作自訂類型,以便開發者可以更好地利用這個特性。結構體Go中的結構體是一種自訂類型,它允許開發者透過將不同類型的變數組合在一起來實現更複雜的資料結構。以下是一個結構體的範例:typePersonstruct{name

使用 Golang 建立自訂類型時的最佳實踐有哪些? 使用 Golang 建立自訂類型時的最佳實踐有哪些? Jun 02, 2024 pm 04:43 PM

在Go中建立自訂類型時遵循以下最佳實務可提升程式碼品質:首字母大寫、使用建議的類型別名、使用struct、使用embed避免重複、實作介面。這些實踐可增強組織性、可讀性和可維護性,例如實戰案例中所展示的購物車類型。

See all articles