目錄
三種檢測對象的類方式: instanceof、constructor 、構造函數名字
用法如下:
1)instanceof
console.log([1,2,3] instanceof Array); true console.log([1,2,3] instanceof Object); true
盡管構造函數是原型的唯一標識,instanceof運算符的右操作數是構造函數,instanceof實際計算過程中檢測的是對象的繼承關系,而不是檢測的創建對象時的構造函數,只是使用了構造函數作為中介
當然也可以使用isPrototypeOf 來判斷一個對象是否存在於另一對象的原型鏈中,此時不使用構造函數作為中介
var a1 = new Array(); console.log(Array.prototype.isPrototypeOf(a1)); true console.log(Array.prototype.isPrototypeOf([1,2,3])); true
注意:多個執行上下文時(例如存在不同框架時)instanceof使用有限制
2)constructor
每個javascript函數都可以用作構造函數,調用構造函數需要使用prototype屬性,因而每個javascript函數會自動擁有prototype屬性,這個屬性值是一個對象,這個對象包含一個contructor屬性,constructor屬性值是一個函數對象。
即對於函數var F = function(){}; F.prototype.constructor===F
關系圖如下:
eg:
var F= function(){}; var p = F.prototype; var c = p.constructor; console.log(p); console.log(c); console.log(c===F);
Object {} function (){} true
因而對象繼承的constructor均指代他們的構造函數
eg:
var o= new F(); console.log(o.constructor===F);
//輸出
true
var a = new Array(); console.log(a.constructor===Array);
//輸出
true
function typeDiscern(x){ switch(x.constructor){ case Number: return "Number:"+x; case String: return "String:"+x; case Array: return "Array:"+x; } } console.log(typeDiscern([1,2,3])); console.log(typeDiscern("abc")); console.log(typeDiscern(5));
//輸出
Array:1,2,3 String:abc Number:5
注意: 同instanceof在多個上下文下沒法使用,另外並不是所有的對象都包含constructor屬性
eg:
定義Person類
function Person(name) { this.name=name; this.getName=function() { return this.name; } }; var wish=new Person('js'); console.log(wish.constructor==Person); console.log(Person.prototype); console.log(Person.constructor); console.log(wish.getName());
//輸出 true Person {} function Function() { [native code] } js
給Person自定義prototype
function Person(name) { this.name=name; this.getName=function() { return this.name; } }; Person.prototype={ toString: function(){ return this.name; } }; var wish=new Person('js'); console.log(wish.constructor==Person); console.log(Person.prototype); console.log(Person.constructor); console.log(wish.getName()); console.log(wish.toString());
//輸出 false Object {toString: function} function Function() { [native code] } js js
此時新定義的原型對象不含有constructor屬性,因而Person的實例也不包含constructor屬性
解決方法:可顯示的給原型添加構造方法
Person.prototype={ constructor=Person, toString: function(){ return this.name; } };
構造函數名字
沒有intanceof和constructor的執行上下文問題,一個窗口中的Array構造函數和另一個窗口內Array構造函數不等,但是構造函數名字相同,但是並不是每個函數都有名字
Function.prototype.getName= function(){ if("name" in this){ return this.name; } return this.name=this.toString().match(/function\s*([^(]*)/); } function test1(){ } console.log(test1.getName());
//輸出: test1
鴨式辨型
關注對象能做什么,而不是對象的類是什么
James Whitcomb Riley提出像鴨子一樣走路、游泳和嘎嘎叫的鳥就是鴨子
主要對象包含walk(),swim(),bike()這三個方法就可以作為參數傳入
利用鴨式辯型實現的函數:
function quackImplements(o/*,...*/){ for(var i=1; i<arguments.length;i++){ var arg=arguments[i]; switch(typeof arg){ case 'string': if(typeof o[arg]!=="function") return false; continue; case 'function': arg=arg.prototype; case 'object': for (var m in arg){ if(typeof arg[m]!=="function") continue; if(typeof o[m]!=="function") return false; } } } return true; }
對於字符串直接檢查命名方法
對於對象檢查是否有同名方法
對於函數檢查構造函數的原型對象中是否有相同方法
在javascript中很多函數都不對對象做類型檢測只是關心這些對象能做什么
eg:Array的prototype利用了鴨式辨型,arguments是偽數組
(function () { var arr = Array.prototype.slice.apply(arguments); console.log(arr); })(1, 2, 3);
//輸出: [1, 2, 3]
var arr = Array.prototype.slice.apply({ 0: 1, 1: 2, 2: 3, length: 3 }); console.log(arr); //輸出: [1, 2, 3]
使用鴨式辨型可以擴大對象的使用范圍
eg:讓普通對象具有數組的push方法
Function.prototype.unCurrying = function () { var f = this; return function () { var a = arguments; return f.apply(a[0], [].slice.call(a, 1)); }; }; Function.prototype.unCurrying = function () { return this.call.bind(this); }; var push = Array.prototype.push.unCurrying(), obj = {}; push(obj, 'first', 'two'); console.log(obj); console.log("length:"+obj.length)
輸出:
Object{0: "first", 1: "two", length: 2}
length:2
參考:javascript權威指南
http://www.cnblogs.com/pigtail/p/3450852.html