原型:
JavaScript是基于原型的我们创建的每个函数都有一个 prototype(原型) 属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
简单来说,就是当我们创建一个函数的时候,系统会分配一个prototype属性,可以用来储存让所有实例共享的属性和方法。
用一张图来表示:
图解:
- 每一个构造函数都拥有一个
prototype属性,这个属性指向一个对象,也就是原型对象 - 原型对象默认拥有一个
constructor属性,指向指向它的那个构造函数 - 每个对象都拥有一个隐藏的属性
__proto__,指向它的原型对象
function Person(){}
var person = new Person();
person.__proto__ === Person.prototype // true
Person.prototype.constructor === Person // true
proto,constructor和prototype是什么?
1. prototype
先看prototype,我们可以百度翻译得知,proto的意思是原型机,也就是可以将prototype翻译为原型对象。这个属性只有函数才会有,不是函数只会输出undefined
2. Porto属性
_proto_相当于子类读取父类的prototype属性的方法(是读取父对象的原型对象不是父对象**),如图,一模一样。
3.constructor
它是从一个对象指向一个函数的。指向的函数就是该对象的构造函数。我们可以打印son的构造函数试一下。
原型的特点:
function Person(){}
Person.prototype.name = 'tt';
Person.prototype.age = 18;
Person.prototype.sayHi = function() {
alert('Hi');
}
var person = new Person();
var person1 = new Person();
person.name = 'oo';
person.name // oo
person.age // 18
perosn.sayHi() // Hi
person1.age // 18
person1.sayHi() //
- 实例可以共享原型上面的属性和方法
- 实例自身的属性会屏蔽原型上面的同名属性,实例上面没有的属性会去原型上面找
原型链:
原型链的定义:JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
- 所有原型链的终点都是
Object函数的prototype属性 Objec.prototype指向的原型对象同样拥有原型,不过它的原型是null,而null则没有原型
关系判断
instanceof
最常用的确定原型指向关系的关键字,检测的是原型,但是只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型
function Person(){}
var person = new Person();
person instanceof Person // true
person instanceof Object // true
hasOwnProperty
通过使用 hasOwnProperty 可以确定访问的属性是来自于实例还是原型对象
function Person() {}
Person.prototype = {
name: 'tt'
}
var person = new Person();
person.age = 15;
person.hasOwnProperty('age') // true
person.hasOwnProperty('name') // false
原型链的问题:
由于原型链的存在,我们可以让很多实例去共享原型上面的方法和属性,方便了我们的很多操作。但是原型链并非是十分完美的
function Person(){}
Person.prototype.arr = [1, 2, 3, 4];
var person1 = new Person();
var person2 = new Person();
person1.arr.push(5)
person2.arr // [1, 2, 3, 4, 5]
引用类型,变量保存的就是一个内存中的一个指针。所以,当原型上面的属性是一个引用类型的值时,我们通过其中某一个实例对原型属性的更改,结果会反映在所有实例上面,这也是原型 共享属性造成的最大问题
另一个问题就是我们在创建子类型(比如上面的 person)时,没有办法向超类型( Person )的构造函数中传递参数
内容参考: JavaScript中的原型与原型链 - 知乎 (zhihu.com))
内容参考:理解原型与原型链 - 知乎 (zhihu.com)
内容参考:原型与原型链 - ENN❤ - 博客园 (cnblogs.com)