幾個關(guān)于類的前提概念:
- 類/繼承描述了一種代碼的組織結(jié)構(gòu)形式梧宫,類意味著復(fù)制;
- 類的核心概念:類、繼承肋层、實例化和多態(tài)【多態(tài)可以簡述為父類的通用行為被子類用更特殊的行為重寫】;
- javascript不存在類翎迁,但基于類是一種設(shè)計模式這一前提栋猖,js通過一些方法近似實現(xiàn)了類的功能;
1.工廠模式
// 工廠模式
function person(name, age, title) {
var o = {}
o.name = name;
o.age = age;
o.title = title;
o.saySomething = function() {
console.log(this.name);
}
return o
}
var person1 = person('孫悟空', 18, '齊天大圣')
var person2 = person('豬八戒', 26, '天蓬元帥')
console.log(person1);
console.log(person2);
打印結(jié)果
{name: "孫悟空", age: 18, title: "齊天大圣", saySomething: ?}
age: 18
name: "孫悟空"
saySomething: ? ()
title: "齊天大圣"
__proto__:
constructor: ? Object()
hasOwnProperty: ? hasOwnProperty()
isPrototypeOf: ? isPrototypeOf()
propertyIsEnumerable: ? propertyIsEnumerable()
toLocaleString: ? toLocaleString()
toString: ? toString()
valueOf: ? valueOf()
__defineGetter__: ? __defineGetter__()
__defineSetter__: ? __defineSetter__()
__lookupGetter__: ? __lookupGetter__()
__lookupSetter__: ? __lookupSetter__()
get __proto__: ? __proto__()
set __proto__: ? __proto__()
問題
- 創(chuàng)建的對象之間沒有任何聯(lián)系汪榔,缺乏可識別的類似類的特性蒲拉;
2.構(gòu)造函數(shù)
// 構(gòu)造函數(shù)模式
function Person(name, age, title) {
this.name = name;
this.age = age;
this.title = title;
this.saySomething = function() {
console.log(this.name);
}
}
var person1 =new Person('孫悟空', 18, '齊天大圣')
var person2 =new Person('豬八戒', 26, '天蓬元帥')
console.log(person1);
console.log(person2);
打印結(jié)果
Person {name: "孫悟空", age: 18, title: "齊天大圣", saySomething: ?}
age: 18
name: "孫悟空"
saySomething: ? ()
title: "齊天大圣"
__proto__:
constructor: ? Person(name, age, title)
__proto__:
constructor: ? Object()
hasOwnProperty: ? hasOwnProperty()
isPrototypeOf: ? isPrototypeOf()
propertyIsEnumerable: ? propertyIsEnumerable()
toLocaleString: ? toLocaleString()
toString: ? toString()
valueOf: ? valueOf()
__defineGetter__: ? __defineGetter__()
__defineSetter__: ? __defineSetter__()
__lookupGetter__: ? __lookupGetter__()
__lookupSetter__: ? __lookupSetter__()
get __proto__: ? __proto__()
set __proto__: ? __proto__()
特征
- 沒有顯式的創(chuàng)建對象
- 屬性和方法直接賦值給this對象
- 沒有return語句
- __ proto __屬性中保存著constructor【構(gòu)造函數(shù)】屬性,該屬性指向Person
問題:
- 方法的重新創(chuàng)建會造成內(nèi)存的浪費
- 將方法定義在全局,然后將引用賦值給this.saySomething雌团,可以解決重復(fù)創(chuàng)建多個相同函數(shù)的問題燃领,但又會引入方法缺乏封裝性的問題
3.原型模式
函數(shù)的prototype屬性:
向構(gòu)造函數(shù)的原型上添加屬性和方法:
function Person() {
}
// 向構(gòu)造函數(shù)的原型上添加屬性和方法
Person.prototype.name = '孫悟空';
Person.prototype.age = 18;
Person.prototype.title = '齊天大圣';
Person.prototype.saySomething = function() {
console.log(this.name);
}
var person1 =new Person()
var person2 =new Person()
console.log(person1);
console.log(person2);
console.dir(Person);
實例對象和構(gòu)造函數(shù)的打印結(jié)果
__ proto __和prototype的解析:
4.原型模式語法的精簡
function Person() {}
// 向構(gòu)造函數(shù)的原型上添加屬性和方法
Person.prototype = {
name: '孫悟空',
age: 18,
title: '齊天大圣',
saySomething: function () {
console.log(this.name);
}
}
var person1 = new Person()
var person2 = new Person()
console.log(person1);
console.log(person2);
console.dir(Person);
打印結(jié)果
這里對prototype賦值對象,完全重寫了prototype,通過以下代碼保證constructor的指向锦援;
Person.prototype = {
// 保證contructor的指向
constructor: Person,
name: '孫悟空',
age: 18,
title: '齊天大圣',
saySomething: function () {
console.log(this.name);
}
}
注意: 此時的constructor的可遍歷性為真猛蔽,原生的是不可遍歷的,可通過Object.defineProperty()進行數(shù)據(jù)屬性的設(shè)置灵寺;
感覺挺重要的3點:
- 實例與原型之間的連接只不過是一個指針曼库,而非是一個副本;
- 原型具有動態(tài)性略板,即可以先創(chuàng)建實例毁枯,之后再在原型上添加新屬性或方法,實例依然能夠讀取原型上的屬性或方法叮称;
- 重寫原型會喪失這種動態(tài)性
原型對象的問題:
function Person() {}
// 向構(gòu)造函數(shù)的原型上添加屬性和方法
Person.prototype = {
// 保證contructor的指向
constructor: Person,
name: '孫悟空',
age: 18,
title: '齊天大圣',
friends: ['八戒', '沙僧'],
saySomething: function () {
console.log(this.name);
}
}
var person1 = new Person()
var person2 = new Person()
//修改其中一個實例person1中的引用類型的屬性值
person1.friends.push('哪吒')
console.log(person1);
console.log(person2);
console.dir(Person);
打印結(jié)果
注:基本屬性的值會產(chǎn)生屏蔽种玛,即在實例上修改同名屬性,會在實例上創(chuàng)建屬性瓤檐,并且通過實例訪問時蒂誉,會遮蔽原型上的同名屬性;
5.構(gòu)造函數(shù)和原型的結(jié)合
簡述就是用構(gòu)造函數(shù)來定義實例屬性【保證實例屬性的獨立性】距帅,原型模式用于定義方法和共享屬性
function Person(name, age, title) {
this.name = name;
this.age = age;
this.title = title;
// 這樣實例的引用類型的屬性就是獨立的了
this.friends = ['八戒', '沙僧']
this.saySomething = function () {
console.log(this.name);
}
}
Person.prototype = {
constructor: Person,
saySomething: function () {
console.log(this.name);
}
}
var person1 = new Person('孫悟空', 18, '齊天大圣')
var person2 = new Person('豬八戒', 26, '天蓬元帥')
console.log(person1);
console.log(person2);
console.dir(Person);