关于 js
的 原型 和 原型链 这个知识点,不光是 面试官问的频率高,我们平时的开发当中,那也是举足轻重啊。一个前端不懂原型和原型链,就好比那无源之水,无本之木。
思考
请想下平常写代码常用的方法如map、filter、every、some
....等等,这些方法从哪里来的?
这些方法其实就是通过原型链共享来的
原型
原型是 Javascript
中的继承的基础,所有 JavaScript
对象都从原型继承属性和方法, JavaScript
的继承就是基于原型的继承。
prototype
-
每一个函数(通常指构造函数),都有一个属性
prototype
, 就是原型(显示原型)。普通对象(例如构造函数new
出来的实例对象)是没有这个属性的(这里为什么说普通对象呢,因为JS里面,一切皆为对象,所以这里的普通对象不包括函数对象)。它是构造函数 的原型对象;这个我在之前的文章里也说过,如果有不了解的小伙伴可以看这儿 (构造函数的特点下面的第7点) -
这个原型(
prototype
)的值是一个对象(object
)
就长这个样子
{
constructor: xxx,
show: function () { } // 这里可以自己添加方法哟!!!
__proto__: yyy,
}
- 添加到原型上的所有方法和属性,被所有
new
出来的实例对象共享。
function Person(name, age) {
this.name = name;
this.age = age;
};
Person.prototype.show = function (params) {
return '我show' + params
}
// console.log(Person.prototype)
const p1 = new Person('张三', 22);
const p2 = new Person('李四', 20);
console.log('p1.show()', p1.show('蒂花之秀'));
console.log('p2.show()', p2.show('造化钟神秀'));
console.log('p1.__proto__=== Person.prototype',p1.__proto__=== Person.prototype);
console.log('Person.prototype.constructor === Person',Person.prototype.constructor === Person);
4. 每一个实例对象,都有一个属性
__proto__
, 叫隐式原型,指向(等于)自己构造函数的显示原型
5. 原型上的
constructor
属性,指向构造函数本身
原型链
JavaScript
通过构造函数 来生成实例。但是有一个问题,在构造函数中通过 this
赋值的属性或者方法,是每个实例自己的的实例属性以及实例方法,他们之间无法共享公共属性(这儿就不举例了,之前的文章已经讲过了,不清楚的小伙伴请移步这儿)。所以设计出了一个原型对象,来存储这个构造函数的公共属性以及方法。原型可以一直追溯往上,形成一个链条式的查找路径,这就是原型链,所以这就是原型链设计的初衷
原型链的基本作用就是属性共享,如果没有原型链,像一些常用的方法例如split,join
这些,每次使用前都得重新定义一遍。
- 构造函数的显示原型(
prototype
),也是一个普通的object
对象,也有自己的__proto__
属性,指向自己构造函数(Object
)的显示原型prototype
Person.prototype.__proto__ === Object.prototype // true
Object.prototype.constructor === Object // true
-
Object.prototype
也是一个普通对象,也有__proto__
, 指向null
Object.prototype.__proto__===null
-
对象方法访问优先级
先自己 ===>沿着原型链往上 (找到就结束,如果直到 Object.prototype
都没有,就不存在 !!!)
先自己,找到就返回
自己没有就往上找父级,找到就返回,没有就继续往上
继续往上
这就是原型和原型链
再给一张草图(Student
是 Person
的子类 不明白 继承 的可以移步这儿,这篇文章就不再赘述了)