对于js的原型和原型链的理解

一、什么是原型:

    任何对象都有一个原型对象,这个原型对象由对象的内置属性_proto_指向它的构造函数的prototype指向的对象,即任何对象都是由一个构造函数创建的,但是不是每一个对象都有prototype,只有方法才有prototype。

  

function Person() {
 
}
 
var p = new Person();
 
//方法才有prototype,普通对象无prototype
 
console.log(Person.prototype); // Object{}
 
console.log(p.prototype); // undifined
 
 
 
//任何对象都是有构造函数的,Person这种方法的构造函数是Function。
 
//备注: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出来对象的构造函数。

二、创建对象的过程(采用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、我们如果用Hello创建一个对象h,看这个对象有什么属性。

 

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属性。

  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,这样就构成了一个原型链。

    三、原型链

    1)什么是原型链?

    原型链的核心就是依赖对象的_proto_的指向,当自身不存在的属性时,就一层层的扒出创建对象的构造函数,直至到Object时,就没有_proto_指向了。

    2)如何分析原型链?

    因为_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

 

     属性搜索原则:
     1.当访问一个对象的成员的时候,会现在自身找有没有,如果找到直接使用。
     2.如果没有找到,则去 原型链指向的对象的构造函数的prototype中找,找到直接使用,没找到就返回undifined或报错。

     3.2、原型链上属性查询的案例

     //略。。。

     3.3、原型继承

    

//原型继承的基本案例
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();

 

posted @ 2020-11-23 16:59  simple-love  阅读(308)  评论(0编辑  收藏  举报