一. 不管是Function, Object, Array
这些都是构造函数。
Function
ƒ Function() { [native code] }
Function.prototype
ƒ () { [native code] }
Function.__proto__
ƒ () { [native code] }
Object
ƒ Object() { [native code] }
Object.prototype
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
Object.__proto__
ƒ () { [native code] }
console.log(Object.__proto__.__proto__)
VM884:1 {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ
Function.prototype.__proto__ === Object.prototype // true
Function.prototype.__proto__ === Object.__proto__.__proto__ // true;
Function.prototype.__proto__
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
Object.__proto__.__proto__
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}constructor: ƒ Object()hasOwnProperty: ƒ hasOwnProperty()isPrototypeOf: ƒ isPrototypeOf()propertyIsEnumerable: ƒ propertyIsEnumerable()toLocaleString: ƒ toLocaleString()toString: ƒ toString()valueOf: ƒ valueOf()__defineGetter__: ƒ __defineGetter__()__defineSetter__: ƒ __defineSetter__()__lookupGetter__: ƒ __lookupGetter__()__lookupSetter__: ƒ __lookupSetter__()get __proto__: ƒ __proto__()set __proto__: ƒ __proto__()
Object.__proto__.__proto__.__proto__
null
使用instanceof
时 左边的对象里的__proto__
对象包含右边这个函数原型的话就是true
;
Object instanceof Function
这里function.prototype (函数原型) 的值为 f() { native code }
,而Object.__proto__
(对象原型)的值现在也为 f () { natvie code } ;
也就是说f () { native code }
这个方法对象是创建 Object,Function, Array
, 包括 RegExp
, String Boolean
这些原始对象之父。 用new
生成的对象。
而且 f () { natvie code } .__proto__
指向了 { }
这个。 而Object.prototype
(对象构造函数的原型) 直接指向了 { }
这个。
所有会有 Function instanceof Object // true
------> 拆解。 Function.__proto__.__proto__ === Object.prototype
用instanceof
判断数组类型
-
typeof
用以获取一个变量的类型,typeof
一般只能返回如下几个结果:number,boolean,string,function,object,undefined
。我们可以使用typeof
来获取一个变量是否存在,如if(typeof a!="undefined"){}
,而不要去使用if(a)
因为如果a
不存在(未声明)则会出错,对于Array,Null
等特殊对象使用typeof
一律返回object
,这正是typeof
的局限性。 -
如果我们希望获取一个对象是否是数组,或判断某个变量是否是某个对象的实例则要选择使用
instanceof
。instanceof
用于判断一个变量是否某个对象的实例,如var a=new Array();alert(a instanceof Array);
会返回true
,同时alert(a instanceof Object)
也会返回true
;这是因为Array
是object
的子类。再如:function test(){};var a=new test();alert(a instanceof test)
会返回true
js中的instanceof
运算符
instanceof
运算符用来判断一个构造函数的prototype
属性所指向的对象是否存在另外一个要检测对象的原型链上
语法
obj instanceof Object;//true 实例obj在不在Object构造函数中
描述
instanceof
运算符用来检测 constructor.prototype
是否存在于参数 object
的原型链上。
实例
重点内容instanceof
的普通的用法,obj instanceof Object
检测Object.prototype
是否存在于参数obj
的原型链上。
Person
的原型在p
的原型链中
function Person(){};
var p =new Person();
console.log(p instanceof Person);//true
继承中判断实例是否属于它的父类
Student
和Person
都在s
的原型链中
function Person(){};
function Student(){};
var p =new Person();
Student.prototype=p;//继承原型
var s=new Student();
console.log(s instanceof Student);//true
console.log(s instanceof Person);//true
复杂用法
这里的案例要有熟练的原型链的认识才能理解
function Person() {}
console.log(Object instanceof Object); //true
//第一个Object的原型链:Object=>
//Object.proto => Function.prototype=>Function.prototype.proto=>Object.prototype
//第二个Object的原型:Object=> Object.prototype
console.log(Function instanceof Function); //true
//第一个Function的原型链:Function=>Function.proto => Function.prototype
//第二个Function的原型:Function=>Function.prototype
console.log(Function instanceof Object); //true
//Function=>
//Function.proto=>Function.prototype=>Function.prototype.proto=>Object.prototype
//Object => Object.prototype
console.log(Person instanceof Function); //true
//Person=>Person.proto=>Function.prototype
//Function=>Function.prototype
console.log(String instanceof String); //false
//第一个String的原型链:String=>
//String.proto=>Function.prototype=>Function.prototype.proto=>Object.prototype
//第二个String的原型链:String=>String.prototype
console.log(Boolean instanceof Boolean); //false
//第一个Boolean的原型链:Boolean=>
//Boolean.proto=>Function.prototype=>Function.prototype.proto=>Object.prototype
//第二个Boolean的原型链:Boolean=>Boolean.prototype
console.log(Person instanceof Person); //false
//第一个Person的原型链:Person=>
//Person.proto=>Function.prototype=>Function.prototype.proto=>Object.prototype
//第二个Person的原型链:Person=>Person.prototype
总结
对应上述规范做个函数模拟A instanceof B
:
function _instanceof(A, B) {
var O = B.prototype;// 取B的显示原型
A = A.proto;// 取A的隐式原型
while (true) {
//Object.prototype.proto === null
if (A === null)
return false;
if (O === A)// 这里重点:当 O 严格等于 A 时,返回 true
return true;
A = A.proto;
}
}
Object instanceof Function
和Function instanceof Object
Object, Function, Array
等等这些都被称作是构造“函数”,他们都是函数。而所有的函数都是构造函数Function
的实例。从原型链机制的的角度来说,那就是说所有的函数都能通过原型链找到创建他们的Function
构造函数的构造原型Function.protorype
对象,所以:
alert(Object instanceof Function);// return true
与此同时,又因为Function.prototype
是一个对象,所以他的构造函数是Object
. 从原型链机制的的角度来说,那就是说所有的函数都能通过原型链找到创建他们的Object
构造函数的构造原型Object.prototype
对象,所以: alert(Function instanceof Object);// return true
有趣的是根据我们通过原型链机制对instanceof
进行的分析,我们不难得出一个结论:Function instanceof Function
依然返回true
, 原理是一样的
Function
是构造函数,所以它是函数对象- 函数对象都是由
Function
构造函数创建而来的,原型链机制解释为:函数对象的原型链中存在Function.prototype
instanceof
查找原型链中的每一个节点,如果Function.prototype
的构造函数Function
的原型链中被查到,返回true
因此下面代码依然返回true
alert(Function instanceof Function);// still true
结论
- 在
JavaScript
语言中,一切的一切都是对象,它们全部继承自Object
.
或者说所有对象的原型链的根节点都是Object.prototype
- 理解原型链机制在
JavaScript
中式如何工作的是非常重要的。掌握了它,不管一个对象多么复杂,你总能够轻而易举地将它攻破。
Object instanceof Function
还是 Function instance of Object
,是真是假,一一道来
如今的JavaScript
再也不是以前被当做玩具的在网页上运行的花哨的脚本了。JavaScript
已经逐渐标准化,作为一门真正的编程语言广泛地应用在Web开发上。因此,越来越多的人开始重新认识这门脚本语言,并在不断地探索关于JavaScript
核心思想和实现原理,过程中遇到了一些非常混淆的问题。本文着重解释一个比较常见但是非常容易使开发人员或者是初学JavaScript
的人非常混淆的问题,那就是两个核心构造函数Object
和Function
,他们之间到底有什么关系?为何instanceof
运算符的返回结果会让你感到混淆?本文将为你一一道来。不过在这之前,我们需要先了解一些JavaScript
中的概念和基本的运行机制。
JavaScript
的对象体系结构
其实在JavaScript
语言中,整个核心的体系结构都围绕着两个构造函数Object
和Function
来构建的。我将引用来自mollypages.org的一张JavaScript对象体系结构图来说明。
图1-1 The JavaScript Object Hierarchy
instanceof
运算符
instanceof
是一个二元运算符,如:A instanceof B
. 其中,A
必须是一个合法的JavaScript
对象,B
必须是一个合法的JavaScript
函数 (function). 判断过程如下:
如果函数B在对象A的原型链 (prototype chain
) 中被发现,那么instanceof
操作符将返回true
,否则返回false
.
例如下面的代码会返回true
.
// return true if specified function is found
// in the object's prototype chain as a constructor.
alert({} instanceof Object);
JavaScript中的原型链(prototype chain
)机制
这里简单概括一下,因为这个话题需要很大篇幅去讨论,本文只是引用了这个概念,重点并非详细讨论该机制。
JavaScript中的原型(prototype
)是和函数(function
)紧密相连的,因为每个函数默认都会有一个属性叫prototype
, 每一个通过函数和new
操作符生成的对象都具有一个属性__proto__
, 这个属性保存了创建它的构造函数的prototype
属性的引用。这个__proto__
对象就是实现原型链的核心对象。JavaScript是一门面向对象的编程语言,它的继承特性其实就是通过原型链机制来实现的。同时,instanceof
运算符也需要在原型链的支持。我们举例说明:
// create a custom constructor Foo
function Foo() {
}
// create an insatnce of Foo
var foo = new Foo();
// foo is an instance of Foo
alert(foo instanceof Foo);// true
// foo is also an instance of Object because
// Foo.prototype is an instance of Object.
// the interpreter will find the constructor
// through the prototype chain.
alert(foo instanceof Object);// true
// Prototype chain of the object foo
//
// __proto__ __proto__ __proto__
// foo -----------> Foo.prototype -----------> Object.prototype -----------> null
// But foo is not an instance of Function, because
// we could not find Function.prototype in foo's
// prototype chain.
alert(foo instanceof Function);// false
// However, its constructor Foo is an instance of
// Function.
alert(Foo instanceof Function);// true
// it's also an instance of Object
alert(Foo instanceof Object);// true
// Prototype chain of the constructor Foo
//
// __proto__ __proto__ __proto__
// Foo -----------> Function.prototype -----------> Object.prototype -----------> null
从上面的代码来分析,我们不难得出这样一个结论:任何对象的原型链最后都能追溯到Object.prototype
. 这也就是我们为什么说JavaScript
中所有的对象都继承自Object
的原因了。
为何Object instanceof Function
和Function instanceof Object
都返回true
?
Object, Function, Array
等等这些都被称作是构造“函数”,他们都是函数。而所有的函数都是构造函数Function
的实例。从原型链机制的的角度来说,那就是说所有的函数都能通过原型链找到创建他们的Function
构造函数的构造原型Function.protorype
对象,所以:
alert(Object instanceof Function);// return true
与此同时,又因为Function.prototype
是一个对象,所以他的构造函数是Object
. 从原型链机制的的角度来说,那就是说所有的函数都能通过原型链找到创建他们的Object
构造函数的构造原型Object.prototype
对象,所以:
alert(Function instanceof Object);// return true
有趣的是根据我们通过原型链机制对instanceof
进行的分析,我们不难得出一个结论:Function instanceof Function
依然返回true
, 原理是一样的
Function
是构造函数,所以它是函数对象- 函数对象都是由
Function
构造函数创建而来的,原型链机制解释为:函数对象的原型链中存在Function.prototype
instanceof
查找原型链中的每一个节点,如果Function.prototype
的构造函数Function
的原型链中被查到,返回true
因此下面代码依然返回true
alert(Function instanceof Function);// still true
结论
-
在JavaScript语言中,一切的一切都是对象,它们全部继承自
Object
. 或者说所有对象的原型链的根节点都是Object.prototype
-
理解原型链机制在JavaScript中式如何工作的是非常重要的。掌握了它,不管一个对象多么复杂,你总能够轻而易举地将它攻破。
一张图看懂Function
和Object
的关系及简述instanceof
运算符
我在写一篇图解prototype
和__proto__
的区别时,搜资料搜到了一个有意思的现象,下面这两个运算返回的结果是一样的:
Function instanceof Object;//true
Object instanceof Function;//true
这个是怎么一回事呢?要从运算符instanceof
说起。
一、instanceof
究竟是运算什么的?
我曾经简单理解instanceof
只是检测一个对象是否是另个对象new
出来的实例(例如var a = new Object()
,a instanceof Object
返回true
),但实际instanceof
的运算规则上比这个更复杂。
首先w3c上有官方解释(传送门,有兴趣的同学可以去看看),但是一如既往地让人无法一目了然地看懂……
知乎上有同学把这个解释翻译成人能读懂的语言(传送门),看起来似乎明白一些了:
//假设instanceof运算符左边是L,右边是R
L instanceof R
//instanceof运算时,通过判断L的原型链上是否存在R.prototype
L.__proto__.__proto__ ..... === R.prototype ?
//如果存在返回true 否则返回false
注意:instanceof
运算时会递归查找L的原型链,即L.__proto__.__proto__.__proto__.__proto__
…直到找到了或者找到顶层为止。
所以一句话理解instanceof
的运算规则为:
instanceof
检测左侧的__proto__
原型链上,是否存在右侧的prototype
原型。
二、图解构造器Function
和Object
的关系
图解构造器
Function
和Object
的关系
我们再配合代码来看一下就明白了:
//①构造器Function的构造器是它自身
Function.constructor=== Function;//true
//②构造器Object的构造器是Function(由此可知所有构造器的constructor都指向Function)
Object.constructor === Function;//true
//③构造器Function的__proto__是一个特殊的匿名函数function() {}
console.log(Function.__proto__);//function() {}
//④这个特殊的匿名函数的__proto__指向Object的prototype原型。
Function.__proto__.__proto__ === Object.prototype//true
//⑤Object的__proto__指向Function的prototype,也就是上面③中所述的特殊匿名函数
Object.__proto__ === Function.prototype;//true
Function.prototype === Function.__proto__;//true
三、当构造器Object
和Function
遇到instanceof
我们回过头来看第一部分那个“奇怪的现象”,从上面那个图中我们可以看到:
Function.__proto__.__proto__ === Object.prototype;//true
Object.__proto__ === Function.prototype;//true
所以再看回第一点中我们说的instanceof
的运算规则,Function instanceof Object
和 Object instanceof Function
运算的结果当然都是true
啦!
如果看完以上,你还觉得上面的关系看晕了的话,只需要记住下面两个最重要的关系,其他关系就可以推导出来了:
1、所有的构造器的constructor
都指向Function
2、Function
的prototype
指向一个特殊匿名函数,而这个特殊匿名函数的__proto__
指向Object.prototype
至于prototype
和__proto__
的关系如何推导,可以参考我写的上一篇博客《三张图搞懂JavaScript的原型对象与原型链》