特權(quán)方法疏橄、公有方法、靜態(tài)方法
function Animal(name) { // Animal是一個基于函數(shù)的“類”
var _name = name; //私有屬性
//特權(quán)方法
this.getName = function() {
return _name;
};
this.setName = function(name) {
_name = name;
};
}
Animal.type = function() {
console.log(this + 'is a private static function') // Animal的私有靜態(tài)方法
}
Animal.prototype.speak = function() { // 定義一個原型方法 在js中也叫做公有方法 也是公有靜態(tài)方法略就, 所有的Animal實例共享一份數(shù)據(jù)
console.log(this.name + ' makes a noise.');
}
var an1 = new Animal()
var an2 = new Animal()
console.log(an1.getName === an2.getName) // false
console.log(an1.speak === an2.speak) // true
console.log(an1.type) // undefined
console.log(an1.speak) // function() ……
如例子所示:Animal是一個基于函數(shù)的“類”捎迫,an1和an2都是一個Animal的對象實例
- 特權(quán)方法:每個對象獨有的方法,每次創(chuàng)建一個實例對象表牢,都會在內(nèi)存中保存一份該特權(quán)方法立砸,特權(quán)方法可以訪問"類"的私有成員
- 公有方法:所有實例對象共享的一份屬性和方法,只會在內(nèi)存中保存一份
- 靜態(tài)方法:可以定義在原型對象中初茶,也可以定義在類上。定義在類上面的方法是類私有的浊闪,實例對象無法獲取恼布,定義在原型中的方法,實例對象可以獲取
- 定義在函數(shù)內(nèi)部的方法和屬性是私有的搁宾,在函數(shù)外部獲取不到折汞,定義在函數(shù)上(如
Animal.type
)的方法和屬性也是私有,不同之處是可以在外部通過Animal.type獲取到
tips:將實例對象的屬性存儲在實例對象中盖腿,公有的屬性存儲在原型中爽待,可以避免創(chuàng)建許多分公有的數(shù)據(jù)和方法,浪費存儲空間(大部分情況下翩腐,方法都是公有的鸟款,存放在prototype中)
prototype和__proto__
如下所示,定義一個Animal類茂卦,Dog和Cat繼承自Animal
function _inherits(subClass, superClass) {
subClass.prototype = Object.create(
superClass && superClass.prototype,
{
constructor: { value: subClass, enumerable: false, writable: true, configurable: true
}
});
subClass.__proto__ = superClass
}
function Animal(name) { // Animal是一個基于函數(shù)的“類”
}
var an1 = new Animal()
var Dog = function (_superClass) {
_inherits(Dog, _superClass)
function Dog() {
return _superClass.apply(this, arguments)
}
return Dog
}(Animal)
var Cat = function (_superClass) {
_inherits(Cat, _superClass)
function Cat() {
return _superClass.apply(this, arguments)
}
return Cat
}(Animal)
var dog1 = new Dog()
var cat1 = new Cat()
console.log(an1.__proto__ === Animal.prototype)
console.log(Dog.__proto__ === Animal)
console.log(Cat.__proto__ === Animal)
console.log(dog1.__proto__ === Dog.prototype)
console.log(cat1.__proto__ === Cat.prototype)
console.log(Dog.prototype.__proto__ === Animal.prototype)
console.log(Cat.prototype.__proto__ === Animal.prototype)
console.log(an1.constructor === Animal)
console.log(cat1.constructor === Cat)
console.log(dog1.constructor === Dog)
根據(jù)上述的輸出何什,Animal、Dog等龙、Cat之間的關(guān)系处渣,以及他們的原
型關(guān)系如圖所示:
總結(jié)出:
- 每個函數(shù)都有一個屬性prototype伶贰,指向?qū)嵗龑ο蟮脑?/li>
- 每個原型對象都有一個constructor,指向構(gòu)造方法
- 每個對象都有一個__proto__罐栈,這項該對象的原型對象
a. 對象可以繼承其原型對象中的方法和屬性
b. __proto__有些瀏覽器不支持(開發(fā)中最好不要使用 __proto__)黍衙,Object.getPrototypeOf(obj)是es5檢索對象的原型(proto)的標(biāo)準(zhǔn)方法
c. 每個對象都有一個 __proto__指向它的原型,這就是原型鏈(prototype chain)
d.instanceof荠诬, object.instanceof(constructor)琅翻,判斷Object的原型鏈中是否存在constructor.prototype,表示一直繼承關(guān)系
繼續(xù)
console.log('\n', Animal.__proto__ === Function.prototype)
console.log(Animal.prototype.__proto__ === Object.prototype)
console.log(Function.__proto__ === Function.prototype)
console.log(Function.prototype.__proto__ === Object.prototype)
console.log(Object.__proto__ === Function.prototype)
console.log(Object.prototype.__proto__ === null)
繼承
如上栗所示浅妆,Dog類繼承Animal類望迎,根據(jù)圖中繼承的關(guān)系,需要執(zhí)行以下步驟
- Dog繼承Animal:
Animal.apply(this, arguments)
凌外,this
指向Dog對象 - 設(shè)置Dog.prototype繼承Animal.prototype辩尊,并且設(shè)置Dog.prototype的constructor指向Dog函數(shù):
Dog.prototype = Object.create(
Animal && Animal.prototype,
{
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
- 設(shè)置
Dog.__proto__ = Animal
上栗babel的extends源碼 -
\_classCallCheck
函數(shù),判斷生成的對象原型鏈上是否存在Constructor.prototype康辑,避免把構(gòu)造函數(shù)當(dāng)做一般函數(shù)使用摄欲,比如把直接調(diào)用Animal()
就會報錯'Cannot call a class as a function' -
\_inherits
函數(shù),設(shè)置subClass. prototype.__proto__ = superClass以及subClass. prototype. constructor = constructor疮薇,設(shè)置subClass.__proto__ = superClass胸墙,.__proto__ 是非標(biāo)準(zhǔn)方法,瀏覽器不支持的時候使用Object.setPrototypeOf(subClass, superClass)
'use strict';
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError('this hasn\'t been initialised - super() hasn\'t been called');
}
return call && (typeof call === 'object' || typeof call === 'function') ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== 'function' && superClass !== null) {
throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype,
{ constructor: { value: subClass, enumerable: false, writable: true, configurable: true }
});
if (superClass) {
Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function');
}
}
var Animal = function Animal(name) {
_classCallCheck(this, Animal);
this.name = name;
};
var Dog = function (_Animal) {
_inherits(Dog, _Animal);
function Dog() {
_classCallCheck(this, Dog);
return _possibleConstructorReturn(this, (Dog.__proto__ || Object.getPrototypeOf(Dog)).apply(this, arguments));
}
return Dog;
}(Animal);