function fn_1(from,to){
var r = Object.create(fn_1.method); // 繼承fn_1.method 所有方法
r.form = from;
r.to = to;
return r;
}
// fn.XXX -> 可以隨意命名,這裡暫且命名為method
fn_1.method={
include: function(x){return this.form <= x && x <= this.to}
}
var callFn_1 = fn_1(1,3);
callFn_1.include(2) // return true;
function Fn_2(from,to){
this.form = from;
this.to = to;
}
// 所有的fn_2物件都會繼承自下面這個物件
// 名稱必須是prototype(強制)
Fn_2.prototype={
incloud: function(x){return this.form <= x && x <= this.to}
}
var callFn_2 = new Fn_2(1,3);
callFn_2.incloud(2) // return true;
var callFn_2 = new Fn_2(1,2);
新創一個Fn_2物件給callFn_2,所以callFn_2也繼承了Fn_2的prototype
callFn_2 instanceof Fn_2
判斷。callFn_2 instanceof Fn_2
並非真的去檢查是否為Fn_2建立的物件,而是檢查callFn_2是否繼承自Fn_2.prototype。建構式需要有prototype的特性,所以每個JavaScript function都具備prototype特性(是一個物件)且裡面僅有一個constructor(不可列舉),且constructor特性值是原來含有此prototype特性的物件。
var Fn = function() { console.log('function fn');}
下面的例子可以看出,prototype特性constructor的值是指向原來含有prototype的物件。
var Fn = function() { console.log('function fn');}
var p = Fn.prototype.constructor;
p === Fn // return true
如果去new一個新的function,先創建的物件(NewFn)會去繼承原函式(Fn)的prototype,放在NewFn原型鍊裡。
var Fn = function() { console.log('function fn');}
var NewFn = new Fn;
var NewFn_A =new Fn;
NewFn.constructor === Fn; //return true
// 比較兩個新創建物件
NewFn_A === NewFn // return false 兩物件並不相等
NewFn_A.constructor === NewFn.constructor //return true
NewFn_A.constructor === NewFn.constructor
兩者相等,可看出兩個新創的物件是繼承自同一個函式。在下面的例子中因為prototype被覆寫了,所以裏頭並沒有constructor
function Fn_2(from,to){
this.form = from;
this.to = to;
}
Fn_2.prototype={
incloud: function(x){return this.form <= x && x <= this.to}
}
所以要在新增原型方法通常會利用以下方式:
function Fn_2(from,to){
this.form = from;
this.to = to;
}
Fn_2.prototype.incloud = function(x){return this.form <= x && x <= this.to}
在JavaScript裡prototype的繼承是動態的。當在新創建一個類別(class)時,會繼承原類別的prototype,在這之後如果有改變原類別的prototype,則新創建的類別所繼承的prototype也會跟著變。
function Fn_3(from,to){
this.form = from;
this.to = to;
}
Fn_3.prototype.incloud = function(x){return this.form <= x && x <= this.to}
var newFn_3 = new Fn_3;
console.dir(newFn_3);
Fn_3.prototype.toString = function(){return this.form+'~'+this.to}
console.dir(newFn_3);
使用typeof XX
可取得類型以剛剛的範例還看newFn_3:typeof newFn_3
return "object"typeof Fn_3
return "function"
在大部分的情況,可能更想得到類別型別。
類似newFn_3類別型別是Fn_3
A instanceof B
判斷A物件是否有B物件的prototype物件。
如果A是繼承B.prototype那A instanceof B
return true。
instanceof 無法直接知道物件的類別,只能用來測試一個物件是否屬於所指定的類別,
function Fn_3(from,to){
this.form = from;
this.to = to;
}
Fn_3.prototype.incloud = function(x){return this.form <= x && x <= this.to}
var newFn_3 = new Fn_3;
newFn_3 instanceof Fn_3 //return true
使用constructor
來取得所屬類別
以上面的例子為例:
newFn_3.constructor
可以看出回傳的是Fn_3 function
並不是每個物件都有constructor特性。(例如今天一開始的那範例callFn_1就沒有contructor)
Duck typing的敘述:(出自James Whitcomb Riley)
When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.
如果一隻鳥走起來像鴨,游起來像鴨,叫起來跟鴨一樣,那就稱這隻鳥為鴨。
用下面簡單的例子說明:
傳入一個物件確認是否為object且有name特性和id特性,如果上述條件都即認定obj就是就是我們自訂的物件,並沒有去深入地確認內層是否一致。
function quacks(obj) {
return obj != null && typeof object === 'object' &&
'name' in obj && 'id' in obj
}