1.判断对象类型
1.1.typeof 运算符
首先要认识到,typepof是一个运算符,其运算需要一个参数,返回值是参数的类型。
-
typeof使用方法
typeof parameter //使用方法1
typeof (parameter) //使用方法2....这两种方式是等效的。 -
typeof的返回值
typeof的返回值,主要有五种: undefined,boolean,number,string,object.
JavaScript主要有五种基本数据类型和一种引用数据类型,所以对于typeof的返回值,容易混淆的一点就是下面的一点typeof null; //"object”
null在js中指的是一个空对象。所以,对于typeof null =="object"也是有其道理的。
1.2.instanceof 运算符
instanceof也是一个运算符,运算过程中也需要一个参数,判断某一个对象是否是所给的构造函数的一个实例,返回值是true或者false;
- instanceof使用方法
parameter1 instanceof parameter2 //使用方法 第一个参数是一个对象,第二个参数是一个函数
parameter1 instanceof (parameter2) //两种方法等效
-
instanceof返回值
instanceof的返回值,只有两种 true 或者false;
1.对于基本数据类型,总是返回false;console.log(null instanceof Object); //false
console.log(true instanceof Boolean); //false
console.log(10 instanceof Number); //false
console.log("sad" instanceof String); //false2.对于一个对象,判断其是否是某一个构造函数的实例;
var object={};
console.log(object instanceof Object);//true function A(){}
console.log(A instanceof Function);//true var B=function(){};
var b=new B();
console.log(b instanceof B);//true
1.3.instanceof的原理
typeof的原理比较简单,主要根据一个其数据类型来返回值。这里我们主要讲解下instanceof的工作原理.
看下面一道例题:
var Animal = function () {
};
var Dog = function () {
};
//子类继承父类的函数
function extend(subClass, superClass) {
var prototype = Object.create(superClass.prototype);
subClass.prototype = prototype;
subClass.prototype.constructor = subClass;
}
extend(Dog, Animal);
var dog = new Dog();
console.log(dog instanceof Dog);//true
console.log(dog instanceof Animal);//true
上面的这道例子,声明了两个类,动物和狗.用狗类实例化一个对象dog.按我们的理解,dog当然属于狗这一类,当时,狗难道不是动物吗? 所以上述两种输出结果都输出true.是合理的。
上述代码执行完毕后,内存中的情况大致是这么样的!
知道了内存中的情况,下面我们来分析一下,代码的执行过程。
执行dog instanceoof Dog的时候
在判断dog对象是否是Dog类的实例的时候,
1.解释器判断dog是否是一个对象,否不是一个对象,则返回false.若是一个对象则跳到第二部。
2.解释器先取得dog的内置属性,然后去取的Dog的函数原型(prototype)。
3.比较dog的内置属性和Dog.prototype是否是同一个对象,若是则返回true.
在执行到第3步的时候,因为则返回true.该句执行结束。
执行dog instanceoof Animal的时候
按照上述步骤执行到第三部,判断dog的内置属性和Animal.prototype不是一个对象,此时接着执行下一步
4.若dog对象的内置属性和Animal类的原型不是同一个对象,则取出dog的内置属性所指向的对象的内置属性
5.判断dog内置属性所指向对象的内置属性是否和Animal.prototype是否指向同一个对象,若是则返回true.
否则,沿着对象内置属性链一直向上查找,一直追溯到null(Objece.prototype.__proto__==null)为止。
简而言之,instanceof比较的时候,
比较的规则是拿对象上的内置属性链上的所有对象与给定的构造函数的原型(prototype)一一比较,直到找到相等的为止。
若比较到最后仍然没有发现两者相等,则返回false.
2.一切皆对象
2.1.为什么说,一切皆是对象呢?
一切皆是对象,这话要从何说起呢!! 看下面的一段代码?
console.log(Function instanceof Object); //true
function a() {
};
console.log(a instanceof Object); //true
如果连函数(function)都是对象,以及函数的构造函数(Function)也是对象,那么我们的确没有理由反对一切皆是对象。但是,怎么证明函数以及函数的构造函数都是对象,这些又是怎么设计的呢?
我们知道,如果是对象。那么身为一个对象,就必须具备对象中最基本的一个属性-----内置属性(内置属性是任何对象都有的一个属性),而且,内置属性最初都起源于Object.prototype.如果这么说的话,那么,我们可以得出一个结论,即 Function和fucntion都具有一个内置属性,且该内置属性直接来自或者间接来自Object.prototype.
现在我们用代码来证明一下是不是这个样子:
console.log(Function.__proto__.__proto__==Object.prototype); //true
如果这个输出结果是真的,那么在内存中的结构就应该是这么个样子:
说道这里,我们能解释了Function是一个对象。接着我们来解释function也是一个对象。
同样的道理,function既然是一个对象,那么肯定也有内置属性,而且function是Function的一个实例,所以其内置属性肯定来源于Function.prototype.那么Function.prototype是什么呢?
console.log(Function.__proto__==Function.prototype);//true
讲到这里,是不是明白了什么呢? 原来Function的内置属性和其原型属性竟然是同一个对象。 好,进行到这里,我们就来一张综合图来分析一下,function Function Object.prototype三者间的关系。
到这里我们算是揭示了一切皆是对象的设计。但是如果想要理解整个设计的架构,我们还需要搞明白一些事情?
即 从图中我们看出,
1.Function的对象的内置属性的constructor指向Function.
因为constructor指向Function ==> Function.__proto__是Function的一个实例 ==> Function.__proto__是一个函数。 ok...证明一下:
console.log(typeof Function.__proto__);//function 这里不要用instanceof判断,如果用instanceof判断,返回结果是false.要想查明原因,请看instanceof工作原理。
到这里也就证明了我们的推论。但是,下面的一个问题来了,所有的对象都有一个内置属性啊。换句话说,Object函数应该有一个内置的[[_proto_]]属性,而Object.prototype也应该有一个内置的[[_proto_]]属性。ok..上面的这幅图片,如果补充完整的话,结果应该如下所示:
上面这幅图片上,我们可以看出,无论一个对象的构造函数是谁,其内置属性最终会回归到最上层的Object.prototype.所以,也就是说一切皆是对象,这句话,不只是说说而已。
注: 上面的这幅图片理解起来不是那么容易。
所以,下面我们来谈谈,怎么看懂上面那副图片?
2.2.为什么要如此设计?
从美学的角度来说,上面的那种设计图真的谈不上美观,第一,它不简单,七拐八绕。第二,很难看出来图片想要表现的是什么!
看懂上面那幅图片,需要有三个最基本的指导思想,
1.一切皆是对象。
2.对象总有一个内置属性,且该内置属性指向其构造函数的prototype属性。
3.函数总有一个prototype属性,该函数在实例化的实话,该属性赋值给实例的内置属性。
明白了上面的三点,下面的几段代码,看看你是否能够回答正确?
function a() {};
console.log(a.__proto__ == Function.prototype);
console.log(Function.__proto__ == Function.prototype);
console.log(Function.__proto__.__proto__ == Function.prototype)
console.log(Object.__proto__ == Function.prototype); //这些代码是为了证明第二点,第一点我们在2.1中已经证明
function a() {};
console.log(a.__proto__ == Function.prototype);
var object={};
console.log(object.__proto__==Object.prototype) //这些代码是为了证明第三点
正因为有上述三种知道指导的存在,所以我们才会使得JS有那么眼花缭乱的效果。
现在,你按着这三种知道思想来考虑一下,是否有比上张图片更好的设计呢!!
注: 在JS中,并不是严格的面向对象,可以说,一切只是技巧的堆砌。不过,这门语言给人的启发的确可以引人深思----面向对象是否有更好的设计呢?
3.总结
总结的部分,其实就是列出一下这篇文章中写作的重点。
首先,分析下typeof和instanceof的比较,目的是掌握instanceof的工作原理。因为在第二部分中,需要大量使用这个函数。
其次,我们逐步分析,一切皆是对象这个观点。然后,用实例来证明观点。
再次,证明一切皆是对象之后,接着来分析,用图片一步步引出,整个设计的轮廓,重点是掌握最后一张图片。因为所有的目的 都是为了证明最后一张图片。
最后,提出这种设计的核心指导思想。你可以比照着这种指导思想仔细阅读第二部分。