js類型判斷及鴨式辨型


 目錄

instanceof

constructor 

構造函數名字

鴨式辨型

 

 

三種檢測對象的類方式: 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

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM