一、原型概述
? ? 任何对象都有一个原型对象,这个原型对象由对象的内置属性_proto_指向它的构造函数的prototyoe指向的对象,即任何对象都是由一个构造函数创建的,被创建的对象都可以获得构造函数的prototype属性,注意:对象是没有prototype属性,只有方法才有prototype属性。
? ? 任何对象都有一个constructor属性,指向创建此对象的构造函数,比如说{}对象,它的构造函数是function Object(){}。
?
function Person() {}var p = new Person();//方法才有prototype,普通对象无prototypeconsole.log(Person.prototype); // Object{} console.log(p.prototype); // undifined//任何对象都是有构造函数constructor,由构造函数创建的对象也可以获得构造函数的引用//此处只是打印下列对象的构造函数是什么。console.log(p.constructor); //function Person(){} console.log(Person.constructor); //function Function(){} console.log({}.constructor); // function Object(){}console.log(Object.constructor); // function Function() {}console.log([].constructor); //function Array(){}? ? 那什么是构造函数呢?
? ? 用function声明的都是函数,而如果直接调用的话,那么Person()就是一个普通函数,只有用函数new产生对象时,这个函数才是new出来对象的构造函数。
二、创建对象的过程
? ? 2.1 、声明方法的过程
????首先,当我们声明一个function关键字的方法时,会为这个方法添加一个prototype属性,指向默认的原型对象,并且此prototype的constructor属性就是此方法。此二个属性会在创建对象时被对象的属性引用。
function Hello() {}console.log(Hello.prototype); // Object {} -- > 内部的constructor 指向Hello方法console.log(Hello.prototype.constructor); // function Hello(){}? 2.2、创建一个对象,从构造函数继承了什么属性?
console.log(h.constructor); // function Hello(){} console.log(Object.getPrototypeOf(h)==Hello.prototype); // true ?备注:getPrototypeOf是获取_proto_? 我们惊喜的发现,new出来的对象,它的constructor指向了方法对象,它的_proto_和prototype相等。
? 即new一个对象,它的_proto_属性指向了方法的prototype属性,并且constructor指向了prototype的constructor属性。
? 由构造函数创建一个对象,此对象多了一个_proto_属性指向构造函数的prototype,一个constructor属性指向构造函数的prototype的constructor属性。
? 2.3 、创建一个对象的过程
function Hehe(name) {this.name = name;}var h = new Hehe("笑你妹");//伪代码:function newObj(name){ var obj = {}; obj.__proto__ = Hehe.prototype; obj.constructor = Hehe.prototype.constructor; var result = Hehe.call(obj, name); return typeof result==='object'&& result!=null ? result : obj; //当无返回对象或默认时返回obj。}var hh = newObj("笑你妹");console.log(hh);console.log(h);//虽然hh!=h,但是可以看到这个hh就和h的结构一样了。? ? 过程:先创建一个空对象,设置一个_proto_指向方法的原型,设置constructor,用新对象做this指向方法,返回新对象。
2.4、总结
????从上面说明的过程中,我们发现只要是对象就是有构造函数来创建的,并且内部二个属性是从构造函数的prototype衍生的一个指向,而构造函数的prototype也是一个对象,那么它应该肯定也有一个构造函数,首先它是一个Object {} 对象,那么它的构造函数肯定是Object,所以就会有一个指针_proto_指向Object.prototype。最后Object.prototype因为没有_proto_,指向null,这样就构成了一个原型链。
? ? 三、原型链分析
? ??什么是原型链?
????原型链的核心就是依赖对象的_proto_的指向,当自身不存在的属性时,就一层层的扒出创建对象的构造函数,直至到Object时,就没有_proto_指向了。
? ??如何分析原型链?
????因为_proto_实质找的是prototype,所以我们只要找这个链条上的构造函数的prototype。其中Object.prototype是没有_proto_属性的,等于null。
? ? 3.1、最简单的原型链分析
function Person(name){ this.name = name; } var p = new Person(); //p ---> Person.prototype --->Object.prototype---->null? ? ?上面原型链的分析:p的构造函数是Person创建的,那么Person.prototype就是继承的第一个原型,而Person.prototype没有自定义设置,默认就是一个Object对象,即是Object构造函数创建的,那么就是继承了Object.prototype,而Object.prototype再往上就没有_proto_指向了,等于null。
? ? 属性搜索原则:
? ? ?1.当访问一个对象的成员的时候,会现在自身找有没有,如果找到直接使用。
? ? ?2.如果没有找到,则去原型链指向的对象的构造函数的prototype中找,找到直接使用,没找到就返回undifined或报错。
? ? ?3.2、原型继承
//原型继承的基本案例function Person(name, age) {this.name = name;this.age = age;}//1.直接替换原型对象 var parent = {sayHello : function() {console.log("方式1:替换原型对象");}}Person.prototype = parent;var p = new Person("坦率的电脑", 50);p.sayHello();//2.混入式原型继承console.log(".............混入式原型继承..............");function Student(name, age) {this.name = name;this.age = age;}var parent2 = {sayHello : function() {console.log("方式2:原型继承之混入式加载成员");}}for ( var k in parent2) {Student.prototype[k] = parent2[k];}var p = new Student("坦率的电脑", 50);p.sayHello();? ? 3.3 原型链案例
// 查询原型链上的对象的方法function findProtoType(obj) { var arr = []; while (obj != null) { obj = Object.getPrototypeOf(obj); arr.push(obj); } return arr;};function Root() {}function Child() {}Child.prototype = new Root();Child.prototype.constructor = Child; // 这个步骤是为了让原型对象打印显示成自身(继承prototype同时也继承了constructor,因此替换成自身)function Item() {}Item.prototype = new Child();Item.prototype.constructor = Item;var result = findProtoType(new Item());console.log(result);// [ Item { constructor: [Function: Item] },Child { constructor: [Function: Child] }, Root {}, {}, null ]谢谢观看!
end!
?
39465824