创建对象的几种方式:
// 第一种方式:字面量var o1 = {name: 'o1'};var o2 = new Object({name: 'o2'});// 第二种方式:构造函数var M = function (name) { this.name = name; };var o3 = new M('o3');// 第三种方式:Object.createvar p = {name: 'p'};var o4 = Object.create(p);
上面几种创建对象的方式,打印出如下结果:
<!DOCTYPE html><html><head><meta charset="utf-8"><title>原型链</title></head><body><script type="text/javascript">// 第一种方式:字面量var o1 = {name: 'o1'};var o2 = new Object({name: 'o2'});// 第二种方式:构造函数var M = function (name) { this.name = name; };var o3 = new M('o3');// 第三种方式:Object.createvar p = {name: 'p'};var o4 = Object.create(p);M.prototype.say = function () {console.log('say hi');};var o5 = new M('o5');var new2 = function (func) {var o = Object.create(func.prototype);var k = func.call(o);if (typeof k === 'object') {return k;} else {return o;}};</script></body></html>
构造函数、原型、实例、原型链

- 构造函数是通过 new 运算符来生成一个实例对象;
- 构造函数也是函数,任何函数都可以作为构造函数;
- 函数都有一个
prototype属性。JS 引擎会在你声明一个函数时自动加上这一个属性( prototype );
原型链:每一个实例对象都有一个 __proto__属性,它指向的是这个对象的原型对象,原型对象也是一个对象,它也会有 __proto__属性,这样就形成了一个链条,称之为 原型链。
M.prototype.constructor === M // trueo3.__proto__ === M.prototype // true
总结
- 函数才会有
prototype属性,对象是没有的; 只有实例对象才会有
__proto__属性。但是函数也有__proto__属性,是为什么呢???因为函数也是一个对象,所以它也会有__proto__属性。M函数也是 Function 构造函数的一个实例对象。M.__proto__ === Function.prototype // true
实例是通过构造函数来生成的,它是怎么和原型对象产生联系的呢???其实就是通过构造函数上的
prototype属性。instanceof 的原理
instanceof运算符:左操作数是一个对象,右操作数是标识对象的类。若左对象是右对象的实例,则表达式返回true,否则返回false。
实例对象是通过构造函数来生成。
实例对象上的__proto__属性,是通过构造函数上的prototype属性来和原型进行关联的。
instanceof 原理:实例对象的__proto__属性和构造函数的prototype属性是否是同一个引用。
注意:只要是原型链上的都会看成是实例对象的构造函数。 ```javascript // 代码延用上侧代码举例
o3 instanceof M // true
o3 instanceof Object // true
o3.proto === M.prototype // true M.prototype.proto === Object.prototype // true
虽然`Object `不是` o3`的构造函数,但是它存在于原型链上,所以说用 `instanceof `来判断 `o3`的构造函数是不是 `Object `是不准确的。怎么准确判断,方法如下:```javascripto3.__proto__.constructor === Object // false
再次举例说明:当通过 instanceof来判断一个对象是否是一个类的实例时,这个判断也会包含对父类的检测。虽然 instanceof的右操作数是构造函数,但计算过程实际是检测了对象的继承关系。
代码举例如下:
var d = new Date();d instanceof Date; // true d是Date的实例d instanceof Object; // true 所有对象都是Object的实例
追加知识
L instanceof R// instanceof运算时,通过判断L的原型链上是否存在R.prototype,若存在返回 true ,否则返回 false// L.__proto__.__proto__.__proto__.__proto__... === R.prototype
具体可查看 手写 instanceof instanceof运算规则为:instanceof 检测左侧的 proto 原型链上,是否存在右侧的 prototype 原型。
图解构造器 Function和 Object关系:
TODO:图
// 1:构造器 Function 的构造函数是自身// Function.constructor ===> ƒ Function() { [native code] }Function.constructor === Function // true// 2:构造器 Object 的构造函数是 Function(由此可知:所有构造器的构造函数都指向 Function)// Object.constructor ===> ƒ Function() { [native code] }// Array.constructor ===> ƒ Function() { [native code] }Object.constructor === Function // true// 3:构造器 Function 的 __proto__ 是一个特殊的匿名函数Function.__proto__ // ƒ () { [native code] }// 4:这个特殊匿名函数的 __proto__ 指向 Object 的 prototype 原型Function.__proto__.__proto__ === Object.prototype // true// 5:Object 的 __proto__ 指向 Function 的 prototype,也就是 3 中说的特殊匿名函数Object.__proto__ === Function.prototype // trueFunction.prototype === Function.__proto__ // trueObject.__proto__ === Function.__proto__ // true
当构造器 Object、Function 用 instanceof来比较
// why??????Object instanceof Function // trueFunction instanceof Object // true// 答案:依据 instanceof 的运算规则就可明白Object.__proto__ === Function.prototypeFunction.__proto__.__proto__ === Object.prototype // true
小结:
- 所有构造器的构造函数(
constructor)都指向Function; Function的prototype指向一个特殊的匿名函数,此匿名函数的__proto__指向Object.prototype。即:Function.prototype.__proto__ === Object.prototype的结果为true。Object是new出来实例对象的基类,function Object() { [native code] };Function是作为众多function出来的函数的基类,function Function() { [native code] };- 构造函数的
__proto__(包括Function和Object)都指向Function.prototype; - 原型对象的
__proto__都指向Object.prototype; Object.prototype.__proto__ === null;- 所有对象(包括:对象、函数)都有
__proto__属性,指向构造该对象的构造函数的原型; - 只有函数
function才具有prototype属性。此属性是一个指针,指向一个对象,此对象的用途就是包含所有实例共享的属性和方法(此对象称为:原型对象)。原型对象也有一个属性,叫做constructor,这个属性包含一个指针,指回原构造函数。new 运算符

模拟 new 运算符:var new2 = function (func) {// func 是一个构造函数var o = Object.create(func.prototype);var k = func.call(o);if (typeof k === 'object') {return k;} else {return o;}};
注意:o6 = new2(M) // Mo6 instanceof M // trueo6 instanceof Object // trueo6.__proto__.constructor === M // true
Object.create()创建对象的对象是用原型链来连接的,o4 的__proto__指向这个p对象 ,也就是指向构造函数的prototype属性,o4.__proto__ === p // true怎么手写一个 new 函数???
isPrototypeOf 、instanceof、hasOwnProperty 三者区别
isPrototypeOf
作用:检测一个对象是否是另一个对象的原型。或者说 一个对象是否被包含在另一个对象的原型链中。 ```javascript var p = {x:1};//定义一个原型对象
var o = Object.create(p);//使用这个原型创建一个对象
p.isPrototypeOf(o);//=>true:o继承p
Object.prototype.isPrototypeOf(p);//=> true p继承自Object.prototype
上例摘自《Javascript 权威指南》,简单解释以下就是:每一个 JS 对象都和原型关联,每一个对象都从原型继承属性。所有通过对象 **直接量** 创建的对象都使用 `Object.prototype` 为他们的原型,因此`p`是继承自 `Object.prototype` ,因此在`p`的原型链中一定存在 `Object.prototype`。<br />`Object.create()` 方法是创建一个新对象,第一个参数是这个新对象的原型。所以上例 创建的 `o`对象,它的原型是 `p`。```javascriptfunction Animal(){this.species = "动物";};var eh = new Animal();Animal.prototype.isPrototypeOf(eh) //=>true
上例是通过 new创建了实例对象 eh,使用构造函数 Animal的 prototype作为它(eh)的原型。
综上两例,发现调用 isPrototypeOf的三种方式如下:
p.isPrototypeOf(o); // trueObject.prototype.isPrototypeOf(p); // trueAnimal.prototype.isPrototypeOf(eh); // true
**isPrototypeOf** 总结如下:
- 通过
Object.create()方法创建的对象,使用第一个参数作为其原型; - 通过对象 直接量 的对象,使用
Object.prototype作为其原型; - 通过
new创建的对象,使用构造函数的prototype属性作为其原型。isPrototypeOf 和 instanceOf 比较
```javascript // A构造函数的prototype对象是否在B的原型链上 B instanceof A
// A对象是否在B的原型链上 A.isPrototypeOf(B)
举例:```javascriptclass A{}class B extends A{}let b = new B();// 这两个类之间的关系B.__proto__ === A //trueB.prototype.__proto__=== A.prototype //trueb.__proto__ === B.prototype //true
为什么会出现如下代码结果。
首先类的继承是按如下方式实现的:
class A {}class B {}// B的实例继承A的实例Object.setPrototypeOf(B.prototype, A.prototype);const b = new B();// B的实例继承A的静态属性Object.setPrototypeOf(B, A);const b = new B();
setPrototypeOf()实现如下:
Object.setPrototypeOf = function (obj, proto) {obj.__proto__ = proto;return obj;}
所以得出前两个结果,也就是如下代码结果:
// 这两个类之间的关系B.__proto__ === A //trueB.prototype.__proto__ === A.prototype //true
而new 操作是按如下方式实现的:
var b = new Object();b.__proto__ = B.prototype;B.call(b);
所有得到第三个表达式: b.__proto__ === B.prototype //true。
接下来看看 instanceof和 isPrototypeOf的表现:
A.isPrototypeOf(B);//trueA.isPrototypeOf(b);//falseb instanceof B;//trueb instanceof A;//trueB instanceof A;//false
再次回头看看三个判断表达式给出的结果就可知:
A对象在B的原型链上,不在b的原型链上,所以:
A.isPrototypeOf(B);//trueA.isPrototypeOf(b);//false
A,B的prototype在b的原型链上而不在B的原型链上,所以:
b instanceof B;//trueb instanceof A;//trueB instanceof A;//false
小结:Y instanceof X判断是的是X的prototype是否在Y的原型链上,而实例的原型链(__proto__)指向的就是其构造函数的prototype,即Y instanceof X判断Y是否是X的一个实例(若Y是X的实例,那他也是X父类的实例)。
而X.isPrototypeOf(Y)判断的是X对象是否在Y的原型链上,同样Y继承X的关系是X对象在Y对象的原型链上,即X.isPrototypeOf(Y)判断X是否继承至Y
hasOwnProperty
对象的 hasOwnProperty() 方法用来检测该属性是否是对象的自有属性。若是对象的自有属性,则返回 true,否则返回 false,false说明该属性是继承属性。
function Animal(){}//定义Animal构造函数Animal.prototype = {//定义Animal原型species:"动物",say:function(){console.log('i can say word');}}function Cat(name,color){//定义构造函数Catthis.name = name;this.color = color;}var F = function(){};F.prototype = Animal.prototype;Cat.prototype = new F();Cat.prototype.constructor = Cat;// Cat继承Animal 用F空对象作为媒介var eh = new Cat('lili','white');//实例化对象console.log('say' in eh)//=>trueconsole.log('name' in eh)//=>trueconsole.log('color' in eh)//=>trueconsole.log('species' in eh)=>trueconsole.log(eh.hasOwnProperty('say'))=>false 由于say为继承属性 非自有属性console.log(eh.hasOwnProperty('species'))=>false 由于species为继承属性 非自有属性console.log(eh.hasOwnProperty('name'))=>trueconsole.log(eh.hasOwnProperty('color'))=>truefor(var key in eh){console.log(key);if(eh.hasOwnProperty(key)){console.log(key) //=>species say name color}}
原型链总图:

