乐趣区

关于javascript:原型与原型链

前言

网上有太多对于原型的材料,不是一上来就各种概念,让人看到摸不着头脑,就是贴各种代码,少个艰深的解释,所以才有了这一篇文章。

原型

用电影的例子来讲,电影的角色个别都会基于某个原型创立进去的,比方最近大火的《你好李焕英》原型就是贾玲的妈妈。

在 JavaScript 中,万物皆对象,每个对象被创立进去都有其对应的一个原型,使对象共享原型的属性与办法,所以原型存在的意义就是解决属性与办法共享的问题,缩小不必要的内存耗费。

上面让咱们来了解下几个小概念:

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

看着下面这张图,让咱们来总结下:

  1. 构造函数 (Person) 通过 prototype 属性指向实例的原型。
  2. person 是基于原型 Person.prototype 创立出的实例, 并且能够通过__proto__属性指向其原型。
  3. Person.prototype 和 person.__proto__都指向实例的原型。

了解了原型的概念,上面我来了解原型链就好了解些了。

原型链

在 JavaScript 中,每个对象通过__proto__属性指向它的原型对象,这个原型对象又有本人的原型,直到某个对象的原型为 null 为止,这种一级一级的链构造就称为原型链。

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

下面咱们给数组原型减少了 first 办法,这让咱们所有数组对象都会共享到这个办法。

总结

原型的存在是 js 的一个重点也是一个难点,
通过本篇,咱们理解了原型与原型链,并且也介绍了一些原型罕用的使用场景来加深咱们对原型与原型链的了解。

退出移动版