目录
三种检测对象的类方式: 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(/functions*([^(]*)/); } 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