原型和原型链

134 阅读4分钟

原型

prototype 原型 函数一声明天生就有

原型的概念:原型是一个可以被复制(或者叫克隆)的一个类,通过复制原型可以创建一个一模一样的新对象。通俗的说,原型就是一个模板,在设计语言中更准确的说是一个对象模板

原型模式: 是用于创建重复的对象,同时又能保证性能,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

(1): 原型是定义了一些公用的属性和方法,利用原型创建出来的新对象实例会共享原型的所有属性和方法

//实例
//创建原型
function Person(name){ 
    this.name = name
      }
      
// 原型的方法
Person.prototype.sayYhl = function(){       
      console.log(this.name + ", hello");                                
 };
 //实例化对象
 var per = new Person("Jack"); 
 var per2 = new Person("Tom");
 
  per.sayYhl();     //Jack, hello
  per2.sayYhl();    //Tom, hello

(2): 严格模式下,原型的属性和方法还是会被原型实例所共享的

    // 开启严格模式,原型的属性和方法还是会被原型实例所共享的
   "use strict";

    // 创建原型
    var Person = function(name){
        this.name = name;
    };

    // 原型的方法
   Person.prototype.sayHello = function(){
       console.log(this.name+",hello");
   };

   // 实例化创建新的原型对象,新的原型对象会共享原型的属性和方法
   var per = new Person("Jack");
   var per2 = new Person("Tom");

   // Jack,hello
   per.sayHello();
   // Tom,hello
   per2.sayHello();

(3):通过原型创建的新对象实例是相互独立的,为新对象实例添加的方法只有该实例拥有这个方法,其它实例是没有这个方法的

 // 创建原型
    var Person = function(name){
        this.name = name;
    };

    // 原型的方法
    Person.prototype.sayYhl = function(){
       console.log(this.name+",hello");
   };

   // 实例化创建新的原型对象,新的原型对象会共享原型的属性和方法
   var per = new Person("Tom");
   var per2 = new Person("Jack");

   // Tom,hello
   per.sayYhl();
   // Jack,hello
   per2.sayYhl();

   
   // 为新对象实例添加方法
   // 通过原型创建的新对象实例是相互独立的
   per.getName = function(){
       console.log(this.name);
   }

   // Tom
   per.getName();
   // Uncaught TypeError: per2.getName is not a function
   per2.getName();

从属关系

prototype -> 函数的一个属性 : 对象 {}
proto -> 对象Object的一个属性 :对象{}
对象的__proto__保存着该对象的构造函数prototype

function Yhl(){}
            console.log(Yhl.prototype);

            const yhl = new Yhl();
            console.log(yhl.__proto__);

 console.log(yhl.__proto__ === Yhl.prototype); //true

 console.log(Yhl.prototype.__proto__ === Object.prototype); //true
 console.log(Object.prototype.__proto__); // null

如图所示:

原型升级版.png

原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。

原型的总结:

  • 所有引用类型都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
  • 所有函数都有一个prototype(原型)属性,属性值是一个普通的对象
  • 所有引用类型的__proto__属性指向它构造函数的prototype

原型的分类
隐式原型(_proto_):上面说的这个原型是JavaScript中的内置属性[[prototype]],此属性继承自object对象,在脚本中没有标准的方式访问[[prototype]],但Firefox、Safari和Chrome在每个对象上都支持一个属性
_proto_,隐式原型的作用是用来构成原型链,实现基于原型的继承 显示原型(prototype):每一个函数在创建之后,便会拥有一个prototype属性,这个属性指向函数的原型对象,显示原型的作用是用来实现基于原型的继承与属性的共享

原型链

1)原型链:原型链是原型对象创建过程的历史记录,当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构

2)原型设计的问题:当查找一个对象的属性时,JavaScript 会根据原型链向上遍历对象的原型,直到找到给定名称的属性为止,直到到达原型链的顶部仍然没有找到指定的属性,就会返回 undefined 也可以理解为原型链继承时查找属性的过程是先查找自身属性,当自身属性不存在时,会在原型链中逐级查找

3)hasOwnProperty 函数:可以用来检查对象自身是否含有某个属性,返回值是布尔值,当属性不存在时不会向上查找对象原型链,hasOwnProperty是 JavaScript 中唯一一个处理属性但是不查找原型链的函数

//console.log(mc.hasOwnProperty("age"));

4)getOwnPropertyNames 函数:可以获取对象所有的自身属性,返回值是由对象自身属性名称组成的数组,同样不会向上查找对象原型链

5)原型链总结

  • 一直往上层查找,直到到null还没有找到,则返回undefined
  • Object.prototype.__proto__ === null
  • 所有从原型或更高级原型中的得到、执行的方法,其中的this在执行时,指向当前这个触发事件执行的对象