instance判断是否属于某个对象上的实例
原型链: 先从js的对象讲起吧,js中万物皆是对象,分为普通对象和函数对象,Object 、Function 是 JS 自带的函数对象
普通对象,函数对象
普通对象是什么,函数对象是什么
一、普通对象:
var simpleObject = {};
var simpleObject = new Object();
var simpleObject = new f1();
function functionObject (){};
var functionObject= function(){};
var functionObject= new Function('str','console.log(str)');
console.log(typeof Object); //function
console.log(typeof Function); //function
console.log(typeof functionObject); //function
console.log(typeof functionObject); //function
console.log(typeof functionObject); //function
console.log(typeof simpleObject); //object
console.log(typeof simpleObject); //object
console.log(typeof simpleObject); //object函数的实例也是object
二、构造函数
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() { alert(this.name) }
}
var person1 = new Person('Zaxlct', 28, 'Software Engineer');
var person2 = new Person('Mick', 23, 'Doctor');
person1和person2都是构造函数Person的实例,这两个实例都有一个constructor(构造函数)属性,这个属性指向构造函数
console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true
得出一个结论,实例的构造函数属性指向构造函数
三、原型对象
js每当定义一个对象时,对象中都会包含一些预定的属性。其中每一个函数对象都会有一个prototype属性,这个属性指向函数的原型对象,那么原型对象要怎么去理解呢?
function Person() {}
Person.prototype.name = 'Zaxlct';
Person.prototype.age = 28;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function() {
alert(this.name);
}
var person1 = new Person();
person1.sayName(); // 'Zaxlct'
var person2 = new Person();
person2.sayName(); // 'Zaxlct'
console.log(person1.sayName == person2.sayName); //true
那什么是原型对象呢?
我们把上面的例子改一改你就会明白了:
Person.prototype = {
name: 'Zaxlct',
age: 28,
job: 'Software Engineer',
sayName: function() {
alert(this.name);
}
}
其实原型对象就是指一个普通的对象,就是指prototype这个属性,这个属性其实是一个对象
在上面我们给这个原型对象添加了四个属性
name、age、job、sayName
但其实prototype这个属性也有一个默认属性constructor,这个属性是一个指针,指向prototype所在的函数Person
Person.prototype.constructor == Person
在上面的构造函数中,我们知道实例也有一个构造属性函数,也是指向构造函数
person1.constructor == Person
那我们试着把这两个公式联系起来
person1.constructor == Person
Person.prototype.constructor == Person
person1为什么会有constructor这个名叫构造函数的属性,因为person1是构造函数Person的实例,所以
Person.prototype也是Person的一个实例
我们试着把Person.prototype想象成A,即
var A = new Person();
Person.prototype = A;
// 注:上面两行代码只是帮助理解,并不能正常运行
所以我们得出结论:(原型对象)Person.prototype也是(构造函数)Person的一个实例
不不,这个结论不够严谨的
原型对象其实就是普通对象(但 Function.prototype 除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性))。看下面的例子:
function Person(){};
console.log(Person.prototype) //Person{}
console.log(typeof Person.prototype) //Object
console.log(typeof Function.prototype) // Function,这个特殊
console.log(typeof Object.prototype) // Object
console.log(typeof Function.prototype.prototype) //undefined
Function.prototype
为什么是函数对象呢?
var A = new Function ();
Function.prototype = A;
上文提到凡是通过 new Function( ) 产生的对象都是函数对象。因为 A 是函数对象,所以Function.prototype
是函数对象。
四、_proto_
js中创建对象时都会有一个_proto_的内置属性,用于指向创造他的构造函数的原型对象
根据上面这个连接图,我们能得到:
person1.constructor = Person;
person1._proto_ = Person.prototype;
Person.prototype.constructor = Person;
五、构造器
我们试着创建一个对象
var obj = {}
它等同于下面这样:
var obj = new Object();
obj是构造函数(Object)的一个实例,所以
obj.constructor === Object
obj.__proto__ === Object.prototype
其实它和上面的构造函数Person差不多,构造函数(Object)本身就是一个函数(即上面说的函数对象)
同理,可以创建对象的构造器不仅仅有 Object,也可以是 Array,Date,Function等。
所以我们也可以构造函数来创建 Array、 Date、Function
var b = new Array();
b.constructor === Array;
b.__proto__ === Array.prototype;
var c = new Date();
c.constructor === Date;
c.__proto__ === Date.prototype;
var d = new Function();
d.constructor === Function;
d.__proto__ === Function.prototype;
六. 原型链
person1.__proto__
是什么?Person.__proto__
是什么?Person.prototype.__proto__
是什么?Object.__proto__
是什么?Object.prototype__proto__
是什么?
答案:
第一题:
因为 person1.__proto__ === person1 的构造函数.prototype
因为 person1的构造函数 === Person
所以 person1.__proto__ === Person.prototype
第二题:
因为 Person.__proto__ === Person的构造函数.prototype
因为 Person的构造函数 === Function
所以 Person.__proto__ === Function.prototype
第三题:Person.prototype
是一个普通对象,我们无需关注它有哪些属性,只要记住它是一个普通对象。
因为一个普通对象的构造函数 === Object
所以 Person.prototype.__proto__ === Object.prototype
第四题,参照第二题,因为 Person 和 Object 一样都是构造函数
第五题:Object.prototype
对象也有proto属性,但它比较特殊,为 null 。因为 null 处于原型链的顶端,这个只能记住。Object.prototype.__proto__ === null
七. 函数对象 (复习一下前面的知识点)
构造函数的构造函数是Function (所有函数对象(包括自定义的构造函数,比如 function Person(){} )的_proto都指向Function.prototype)
Number.__proto__ === Function.prototype // true
Number.constructor == Function //true
// 所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
Object.__proto__ === Function.prototype // true
Object.constructor == Function // true
// 所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
Function.__proto__ === Function.prototype // true
Function.constructor == Function //true
JavaScript中有内置(build-in)构造器/对象(Number,String,Boolean,Object,Function,Array,RegExp,Error,Date,Math,JSON,Global,Arguments)共计12个(ES5中新加了JSON),这里列举了可访问的8个构造器。剩下如Global不能直接访问,Arguments仅在函数调用时由JS引擎创建,Math,JSON是以对象形式存在的,无需new。它们的proto是Object.prototype。如下
Math.__proto__ === Object.prototype // true
Math.construrctor == Object // true
JSON.__proto__ === Object.prototype // true
JSON.construrctor == Object //true
这说明什么呢?
所有的构造器都来自于 Function.prototype
,甚至包括根构造器Object
及Function
自身。所有构造器都继承了·Function.prototype·的属性及方法。如length、call、apply、bind
Function.prototype
也是唯一一个typeof XXX.prototype
为 function
的prototype
。其它的构造器的prototype
都是一个对象(原因第三节里已经解释过了)。如下(又复习了一遍):
console.log(typeof Function.prototype) // function
console.log(typeof Object.prototype) // object
console.log(typeof Number.prototype) // object
console.log(typeof Boolean.prototype) // object
console.log(typeof String.prototype) // object
console.log(typeof Array.prototype) // object
console.log(typeof RegExp.prototype) // object
console.log(typeof Error.prototype) // object
console.log(typeof Date.prototype) // object
console.log(typeof Object.prototype) // object
噢,上面还提到它是一个空的函数,console.log(Function.prototype)
下看看(留意,下一节会再说一下这个)
知道了所有构造器(含内置及自定义)的__proto__
都是Function.prototype
,那Function.prototype
的__proto__
是谁呢?
相信都听说过JavaScript中函数也是一等公民,那从哪能体现呢?如下console.log(Function.prototype.__proto__ === Object.prototype) // true
这说明所有的构造器也都是一个普通 JS 对象,可以给构造器添加/删除属性等。同时它也继承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。(你也应该明白第一句话,第二句话我们下一节继续说,不用挖坑了,还是刚才那个坑;))