本文共 1475 字,读完只需 6 分钟javascript
在 JavaScript 中,是一种面向对象的程序设计语言,可是 JS 自己是没有 “类” 的概念,JS 是靠原型和原型链实现对象属性的继承。java
在理解原型前,须要先知道对象的构造函数是什么,构造函数都有什么特色?浏览器
1. 构造函数bash
// 构造函数 Person()
function Person(name, gender) {
this.name = name;
this.gender = gender;
}
var person = new Person("周杰伦", "男");
// 最后建立出来的对象实例 person
person
{
name: "周杰伦",
gender: "男"
}
复制代码
以上代码,普通函数 Person()
,加上 new
关键字后,就构造了一个对象 person
微信
因此构造函数的定义就是普通函数加上 new
关键字,并总会返回一个对象。闭包
2. 函数对象
同时,JS 中的对象分为通常对象和函数对象。那什么是通常对象,什么又是函数对象呢?app
JavaScript 的类型分为基本数据类型和引用数据类型,基本数据类型目前有 6 种(null, undefined, string, number, boolean, Symbol)。 其他的数据类型都统称为 object 数据类型,其中,包括 Array, Date, Function等,因此函数能够称为函数对象。函数
let foo = function(){
}
foo.name = "bar";
foo.age = 24;
console.log(foo instanceof Function) //true
console.log(foo.age) // 24
复制代码
以上代码就说明了函数实际上是一个对象,也能够具备属性。post
JavaScript 中的对象,有一个特殊的 [[prototype]]
属性, 其实就是对于其余对象的引用(委托)。当咱们在获取一个对象的属性
时,若是这个对象上没有这个属性,那么 JS 会沿着对象的 [[prototype]]
链 一层一层地去找,最后若是没找到就返回 undefined
;ui
这条一层一层的查找属性的方式,就叫作原型链。
var o1 = {
age: 6
}
复制代码
那么,为何一个对象要引用,或者说要委托另一个对象来寻找属性呢?
本文开篇的第一句话,就指出来的,JavaScript 中,和通常的 OOP 语言不一样,它没有 '类'的概念,也就没有 '模板' 来建立对象,而是经过字面量或者构造函数的方式直接建立对象。那么也就不存在所谓的类的复制继承。
那什么又是原型呢?
既然咱们没有类,就用其余的方式实现类的行为吧,看下面这句话↓↓。
1. 每一个函数都有一个原型属性 prototype 对象
function Person() {
}
Person.prototype.name = 'JayChou';
// person1 和 person2 都是空对象
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // JayChou
console.log(person2.name) // JayChou
复制代码
经过构造函数创造的对象,对象在寻找 name
属性时,找到了 构造函数的 prototype
对象上。
这个构造函数的 prototype
对象,就是 原型
用示意图来表示:
查找对象实例属性时,会沿着原型链向上找,在现代浏览器中,标准让每一个对象都有一个 __proto__
属性,指向原型对象。那么,咱们能够知道对象实例和函数原型对象之间的关系。
2. 每一个原型对象都有一个 constructor 属性指向关联的构造函数
为了验证这一说话,举个例子。
function Person() {}
Person === Person.prototype.constructor; // true
复制代码
那么对象实例是构造函数构造而来,那么对象实例是否是也应该有一个 constructor
呢?
function Person() {}
const person = new Person();
person.constructor === Person // true
复制代码
但事实上,对象实例自己并无 constructor
属性,对象实例的 constructor 属性来自于引用了原型对象的 constructor
属性
person.constructor === Person.prototype.constructor // true
复制代码
3. 原型链顶层:Object.prototype.__proto__
== null
既然 JS 经过原型链查找属性,那么链的顶层是什么呢,答案就是 Object 对象,Object 对象其实也有 __proto__
属性,比较特殊的是 Object.prototype.__proto__
指向 null
, 也就是空。
Object.prototype.__proto__ === null
复制代码
咱们回过头来看函数对象:
全部函数对象的proto都指向Function.prototype,它是一个空函数(Empty function)
Number.__proto__ === Function.prototype // true
Number.constructor == Function //true
Boolean.__proto__ === Function.prototype // true
Boolean.constructor == Function //true
String.__proto__ === Function.prototype // true
String.constructor == Function //true
// 全部的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
Object.__proto__ === Function.prototype // true
Object.constructor == Function // true
// 全部的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
Function.__proto__ === Function.prototype // true
Function.constructor == Function //true
Array.__proto__ === Function.prototype // true
Array.constructor == Function //true
RegExp.__proto__ === Function.prototype // true
RegExp.constructor == Function //true
Error.__proto__ === Function.prototype // true
Error.constructor == Function //true
Date.__proto__ === Function.prototype // true
Date.constructor == Function //true
复制代码
全部的构造器都来自于 Function.prototype,甚至包括根构造器Object及Function自身。全部构造器都继承了·Function.prototype·的属性及方法。如length、call、apply、bind
以图会友,这就是网上常常看到的 JS 原型和原型链关系图:
对于以上看似很复杂的关系图,只须要理解 5 点:
Person.prototype.__proto__ === Object.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__
是 null以上就是 JavaScript 中原型和原型链的知识。因为 JS 没有'类', 因此采用了原型的方式实现继承,正确的说法是引用或者委托,由于对象之间的关系不是复制,而是委托。在查找属性的时候,引用(委托)原型对象的属性,也就是咱们常说的原型继承。
欢迎关注我的微信订阅号,专一分享原创文章