對象的屬性:
私有屬性(var)、類屬性(靜態屬性)、對象屬性(this)、原型屬性(prototype)。
對象的方法:
私有方法(funtion)、類方法(靜態方法)、對象方法(this)、原型方法(prototype)。
類方法/靜態方法:
類名.方法名 = function(參數1,參數2...參數n)
{
//方法代碼
}
對象方法:this指針(公有方法/特權方法)
原型方法:
類名.prototype.方法名 = function(參數1,參數2...參數n)
{
//方法代碼
}
1.私有屬性 私有方法:只能在這個函數里使用這個屬性或方法
function User(name,age){
var name = name;//私有屬性
var age = age;
function alertAge(){//私有方法
alert(age);
}
alertAge(age); //彈出26
}
var user = new User('fire子海',26);
私有屬性也可以通過閉包獲取。
2.靜態屬性: 公共屬性,直接屬於某個類,即類屬性(js沒有類,這里只是指構造函數)
靜態屬性的定義方式是:
類名.屬性名=屬性值; 使用 【類名.屬性名】 調用
靜態方法:只有類才能訪問類屬性和方法,實例不能訪問,只能通過對象本身調用靜態方法和靜態屬性。
靜態屬性方法是暴露給外部的,掛在類上面的,不屬於任何實例。
靜態方法無法調用公有屬性、公有方法、私有方法、私有屬性、特權方法、原型屬性
靜態方法的定義方式是:
類名.方法名 = function(參數1,參數2...參數n)
{
//方法代碼
}
如果兩個函數都調用這個靜態方法,刪除其中一個函數中的靜態方法,則對應的另一個函數的靜態方法也被刪除。
靜態方法表現形式:
Eg1:
function User(){}
User.age = 26;//靜態屬性
User.myname = 'fire子海';
User.getName =function(){//靜態方法
return this.myname;
}
console.log(User.getName());//output:fire子海
Eg2://靜態類 字面量方式
var user = {
init:function(name,age){ //靜態方法
this.name = name;
this.age = age;
},
getName:function(){
return this.name;
}
}
user.init('fire子海',26);
console.log(user.getName());//output:fire子海
Eg3://靜態方法不能實例訪問
function User(){}
User.age = 26;//靜態屬性
User.myname = 'fire子海';
User.getName =function(){//靜態方法
return this.myname;
}
var user = new User();
console.log(user.getName);//undefined 或者user.getName()返回TypeError: user.getName is not a function
user.supper = '方便面';
user.eat = function(){
return '晚餐只有'+this.supper;
}
user.eat();//晚餐只有方便面 //給new對象加方法所以可以調用
Eg4://構造函數+原型
function User(){
this.myname = 'fire子海';//公有屬性
this.age = 26;
this.do = function(){//特權方法
return this.myname+'學習js';
}
}
User.prototype.alertAge = function(){//公共方法,也叫原型方法
alert(this.age);
}
User.prototype.sex = '男';//原型屬性
User.getName= function(){//靜態方法
return this.myname;
}
User.getAge = function(){
this.alertAge();
}
User.getDo = function(){
return this.do();
}
//console.log(User.getName())//undefined 靜態方法不能調用公有屬性
//console.log(User.getDo());//TypeError: this.do is not a function //靜態方法不能調用特權方法
//console.log(User.getAge())//TypeError: this.alertAge is not a function//靜態方法不能調用原型方法和原型屬性
3.公有屬性:(即實例屬性、特權屬性,)在對象實例化后調用。
公有方法的調用規則:
公有方法能被外部訪問並調用的方法。通過對象本身調用,即對象名。公有方法不能調用私有屬性和方法。
公有方法和特權方法並沒有什么本質上的區別,原因在於這個概念是來自於使用構造函數創建私有數據的時候定義出來的。
Eg:
var BaseClass = function() {
this.method1 = function(){
alert(' Defined by the "this" in the instance method');
}
};
var instance1 = new BaseClass();
instance1.method1 = function(){
alert(' Defined directly in the instance method');
}
BaseClass.prototype.method1 = function(){
alert(' Defined by the prototype instance method ');
}
instance1.method1();//Defined directly in the instance method
通過運行結果跟蹤測試可以看出直接定義在實例上的變量的優先級要高於定義在“this”上的,而定義在“this”上的又高於 prototype定義的變量。即直接定義在實例上的變量會覆蓋定義在“this”上和prototype定義的變量,定義在“this”上的會覆蓋prototype定義的變量。
直接定義變量>this定義變量>prototype定義變量
Eg://構造函數+原型
function User(){
this.myname = 'fire子海';//公有屬性
this.age = 26;
this.do = function(){ //特權方法
return this.myname+'學習js';
}
}
User.eat = function(food){ //靜態方法
return '晚餐只有'+food;
}
User.prototype.alertAge = function(){//原型方法 可以調用公有屬性/實例屬性
alert(this.age);
}
User.prototype.alertDo = function(){
alert(this.do());//原型方法可以調用特權方法
}
User.prototype.alertEat = function(food){
alert(User.eat(food));//只能通過對象本身調用靜態方法
//alert(this.ear(food))這樣調用將出錯:this.eat is not a function
}
var user = new User();
user.alertAge();//alert:26
user.alertDo();//alert:fire子海學習js
user.alertEat('方便面')//alert:晚餐只有方便面
4.原型屬性 原型方法
原型屬性:類名.prototype.屬性名 = 屬性值;
原型方法:
類名.prototype.方法名 = function(參數1,參數2...參數n)
{
//方法代碼
};
User.prototype.alertAge = function(){//公共方法,也叫原型方法
alert(this.age);
}
User.prototype.sex = '男';//原型屬性
當作是類內部的屬性使用【this.原型屬性】,也可以當成公有靜態屬性使用【對象.prototype.原型屬性】 靜態方法不能調用原型屬性
原型方法可以實例化對象調用,也可靜態方法調用
在實例上不能使用prototype,否則發生編譯錯誤
Eg:
var obj = new Object();
obj.prototype.Property = 1; //Error
obj.prototype.Method = function(){alert(1); }//Error
每個由構造器創建的對象擁有一個指向構造器 prototype 屬性值的 隱式引用(implicit reference),這個引用稱之為 原型(prototype)。進一步,每個原型可以擁有指向自己原型的 隱式引用(即該原型的原型),如此下去,這就是所謂的 原型鏈(prototype chain)。在具體的語言實現中,每個對象都有一個 __proto__ 屬性來實現對原型的 隱式引用。
有了 原型鏈,便可以定義一種所謂的 屬性隱藏機制,並通過這種機制實現繼承。
<script type="text/javascript"> //子類如何重寫父類的屬性或方法
function AClass() {
this.Property = 1;
this.Method = function() { alert(1); }
}
function AClass2(){
this.Property2 = 2;
this.Method2 = function() {alert(2); }
}
AClass2.prototype = new AClass();
AClass2.prototype.Property = 3;
AClass2.prototype.Method = function() { alert(4); }
var obj = new AClass2();
alert(obj.Property); //3
obj.Method(); //4
</script>
靜態方法和實例方法區別:
當然你完全可以把所有的實例方法都寫成靜態的,將實例作為參數傳入即可,一般情況下可能不會出什么問題。
從面向對象的角度上來說,在抉擇使用實例化方法或靜態方法時,應該根據是否該方法和實例化對象具有邏輯上的相關性,如果是就應該使用實例化對象,反之使用靜態方法。
如果從線程安全、性能、兼容性上來看,也是選用實例化方法為宜。
<script type="text/javascript">
var fun = {
//下面是靜態方法(第一種方式)
f1: function () {
alert("這是靜態方法 f1()");
},
f2:function(callback){
alert("這是靜態方法 f2()");
if(callback && (callback instanceof Function)){
callback();//回調方法
}
}
}
var c = function () {
//實例方法
this.f1=function(){
alert("這是實例方法 c.f1()");
}
}
//下面是靜態方法(第二種方式)
c.f2 = function () {
alert("這是靜態方法 c.f2()");
}
callbackfun = function () {
alert("這是定義好的回調方法!");
}
$(function () {
var node = document.getElementById('test');
node.onclick = function () {
//調用靜態方法
fun.f1();
//調用回調方法
fun.f2(function () { alert("這是回調方法!");});
fun.f2(callbackfun);
//調用靜態方法
c.f2();
//調用實例方法
var c1 = new c();
c1.f1();
//c1.f2();//這樣不能調用會報錯
//alert(typeof (fun));//obj
//alert(typeof (fun.f1));//function
//alert(typeof(c.f2)); //function
//var c1 = new c();
//alert(typeof (c));//function
//alert(typeof(c1));//object
//alert(typeof(c1.f1));//function
}
});
</script>