与大部分面向对象语言不一样,ES6以前中并无引入类(class)的概念,JavaScript并不是经过类而是直接经过构造函数来建立实例。在介绍原型和原型链以前,咱们有必要先复习一下构造函数的知识。javascript
构造函数模式的目的就是为了建立一个自定义类,而且建立这个类的实例。构造函数模式中拥有了类和实例的概念,而且实例和实例之间是相互独立的,即实例识别。
构造函数就是一个普通的函数,建立方式和普通函数没有区别不一样的是构造函数习惯上首字母大写。 另外就是调用方式的不一样,普通函数是直接调用,而构造函数须要使用new关键字来调用。java
function Person(name, age, gender) { this.name = name this.age = age this.gender = gender this.sayName = function () { alert(this.name); } } var per = new Person("孙悟空", 18, "男"); function Dog(name, age, gender) { this.name = name this.age = age this.gender = gender } var dog = new Dog("旺财", 4, "雄") console.log(per);//当咱们直接在页面中打印一个对象时,事件上是输出的对象的toString()方法的返回值 console.log(dog);
每建立一个Person构造函数,在Person构造函数中,为每个对象都添加了一个sayName方法,也就是说构造函数每执行一次就会建立一个新的sayName方法。这样就致使了构造函数执行一次就会建立一个新的方法,执行10000次就会建立10000个新的方法,而10000个方法都是一摸同样的,为何不把这个方法单独放到一个地方,并让全部的实例均可以访问到呢?这就须要原型(prototype
)node
在JavaScript中,每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个prototype
属性,这个属性指向函数的原型对象,而且这个属性是一个对象数据类型的值。web
让咱们用一张图表示构造函数和实例原型之间的关系:
原型对象就至关于一个公共的区域,全部同一个类的实例均可以访问到这个原型对象,咱们能够将对象中共有的内容,统一设置到原型对象中。shell
__proto__
和constructor
每个对象数据类型(普通的对象、实例、prototype......
)也天生自带一个属性__proto__
,属性值是当前实例所属类的原型(prototype
)。原型对象中有一个属性constructor
, 它指向函数对象。svg
function Person() {} var person = new Person() console.log(person.__proto__ === Person.prototype)//true console.log(Person.prototype.constructor===Person)//true //顺便学习一个ES5的方法,能够得到对象的原型 console.log(Object.getPrototypeOf(person) === Person.prototype) // true
在JavaScript中万物都是对象,对象和对象之间也有关系,并非孤立存在的。对象之间的继承关系,在JavaScript中是经过prototype对象指向父类对象,直到指向Object对象为止,这样就造成了一个原型指向的链条,专业术语称之为原型链。函数
举例说明:person → Person → Object ,普通人继承人类,人类继承对象类学习
当咱们访问对象的一个属性或方法时,它会先在对象自身中寻找,若是有则直接使用,若是没有则会去原型对象中寻找,若是找到则直接使用。若是没有则去原型的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,若是在Object原型中依然没有找到,则返回undefined。测试
咱们能够使用对象的hasOwnProperty()
来检查对象自身中是否含有该属性;使用in检查对象中是否含有某个属性时,若是对象中没有可是原型中有,也会返回truethis
function Person() {} Person.prototype.a = 123; Person.prototype.sayHello = function () { alert("hello"); }; var person = new Person() console.log(person.a)//123 console.log(person.hasOwnProperty('a'));//false console.log('a'in person)//true
person实例中没有a这个属性,从 person 对象中找不到 a 属性就会从 person 的原型也就是 person.__proto__
,也就是 Person.prototype
中查找,很幸运地获得a的值为123。那假如 person.__proto__
中也没有该属性,又该如何查找?
当读取实例的属性时,若是找不到,就会查找与对象关联的原型中的属性,若是还查不到,就去找原型的原型,一直找到最顶层Object为止。Object是JS中全部对象数据类型的基类(最顶层的类)在Object.prototype
上没有__proto__
这个属性。
console.log(Object.prototype.__proto__ === null) // true
使用node 进行测试
C:\Users\Lenovo>node > function Person(){} undefined > let person = new Person(); undefined > console.log(person == Person) false undefined > console.log(person == Person.prototype) false undefined > console.log(person.__proto__ == Person.prototype) true undefined > console.log(person.constructor == Person) true undefined > console.log(Person.prototype.constructor == Person) true undefined > console.log(person.constructor == Person.prototype.constructor) true undefined >
根据测试得出:原型对象(Person.prototype
)是 构造函数(Person
)的一个实例。
然而实例对象(person
)与构造函数(Person
)并不存在直接联系;
而是创建在实例对象(person
)的__proto
与构造函数(Person
)的原型对象(Person.prototype
)之间,而后再进行对构造函数的访问与操做