原型与原型链

112 阅读3分钟

什么是原型

在JavaScript中,每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值

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

  • prototype 我们知道在JS中每次创建一个函数,该函数就会自动带有一个prototype属性,该属性指向函数的原型对象。
function Person(age) {
    this.age = age       
}
Person.prototype.name = 'qiyue'//原型增加一个name属性
console.log(Person.prototype) //输出原型对象 {name: 'qiyue', constructor: ƒ}
var person1 = new Person()
var person2 = new Person()
console.log(person1.name) //qiyue 共享原型属性
console.log(person2.name)  //qiyue 共享原型属性

上述中,函数的prototype指向了一个对象,而这个对象正是调用构造函数时创建的实例的原型,也就是person1和person2的原型。

  • proto

这是js对象中(null和undefined除外)都会存在的属性,这个属性会指向该对象的原型(注意:__proto__因为浏览器兼容性问题,不一定都可以获取到,应当使用Object.getPrototypeOf函数作为获取对象原型的标准API)。

function Person() {
}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true

什么是原型链

原型链就是创建一个构造函数,它会默认生成一个prototype属性并指向原型对象。使用下一个构造函数的原型对象作为这个构造函数的实例。即 nextFuction.prototype = new thisFuction();
在下一个构造函数的原型对象 = new nextFuction。这样下去就会构成一条实例与原型之间的链条,这就是原型链。

function Person(age){
  this.age = age
}
Person.prototype.name = 'qiyue'
var person = new Person();
console.log(person.__proto__);//Person.prototype=> {name: 'qiyue', constructor: ƒ}
console.log(person.__proto__.__proto__);//Object.prototype=>{constructor: ƒ,…}
console.log(person.__proto__.__proto__.__proto__);//null

当你用构造函数(Person)建立一个对象时,它的原型链就是: person ==》 Person.prototype ==》 Object.prototype ==》 null 再来看下对象属性的搜索

Person.prototype = {age:24};
var person = new Person("qiyue");
console.log(person.name);//qiyue
console.log(person.age);//24

对象属性的搜索是作用于整条原型链上的。搜索会从原型链头开始,直到原型链的末端,寻找这个属性,这个例子中name属性就在对象本身找到的(person),而age是在原型中找到的(Person.prototype)。

运用

  • instanceOf
function instanceOf(left, right)
{
    if (typeof left !== 'object' || left === null) return false;
    let proto = Object.getPrototypeOf(left);
    while (true)
    {   //循环往下寻找,直到找到相同的原型对象
        if (proto === null) return false;
        if (proto === right.prototype) return true;//找到相同原型对象,返回true
        proto = Object.getPrototypeOf(proto);
    }
}
console.log(instanceOf(person,Person));//true
console.log(instanceOf(person,Object));//true
console.log(instanceOf(person,Array));//false

instanceOf原理就是寻找构造函数的原型(prototype)是否在这个对象的原型链上。

  • 继承
function Person(){
    this.say = function (){
        console.log("hello");
    }
}
function Student(){
}
function Teacher(){
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
Teacher.prototype = new Person();
Teacher.prototype.constructor = Teacher;
var s = new Student();
s.say();
var t = new Teacher();
t.say();

Student需要say方法,Teacher也需要say方法,那我们可以把共有的行为通过原型继承的方式共享say方法。

  • 扩展原型方法
var nums = new Array(1,2,3);
/**添加一个返回数组的第一个元素的新方法。 */
Array.prototype.first = function ()
{
    return this[0];
}
console.log(nums.first());//1