(一)原型、原型链
原型和原型链
什么是原型?
我们创建的每一个构造函数都有一个 prototype
属性,它指向一个对象,这个对象可以包含由该函数创建的所有实例共享 属性和方法。
prototype
就是调用构造函数创建的实例的原型对象。
使用原型对象的好处?
可以让所有的对象实例共享它所包含的属性和方法。
构造函数、实例、原型对象的关系?
每个构造函数都有一个原型对象。也就是prototype
。
每个原型对象都有一个指向构造函数的属性,就是constructor
。
每个实例都有一个__proto__
属性,指向原型对象。
__proto__
被称为隐式原型,prototype
被称为显式原型,也就是说一个对象的隐式原型指向了该对象的构造函数的显式原型
。在显式原型上
定义的属性和方法,通过隐式原型传递给了构造函数的实例,这样实例就能访问到构造函数原型上的属性和方法了。
什么是原型链?
prototype
机制就是存在于对象中的一个内部链接,它会引用其他对象。
如果在当前对象没有找到想要的属性或方法时,js 引擎就会沿着 prototype
关联的对象继续查找,以此类推。这一系列对象的链接就被称为原型链。
原型链最顶端是 Object.prototype
, 它的__proto__
仍然存在,为 null。
构造函数
构造函数里可以有实例成员和静态成员
实例成员:就是在构造函数内部,通过
this
添加的成员。实例成员可以通过实例对象来访问。静态成员:在构造函数本身上添加的成员,只能通过构造函数来访问。
1 | function Star(name, age) { |
问题扩展
通过构造函数创建的每个实例的方法是共享的吗?
不一定,分两种情况讨论:
- 在构造函数上直接定义的方法不共享。
1 | function Star() { |
每次生成实例都会新开辟一块内存存储属性和方法。
如果属性是基本类型,就不存在共享的问题,具体是否相同要看具体值的内容是否相同。
- 通过原型添加的方法是共享的。
1 | function Star(name) { |
综上得出定义构造函数的规则。
: 公共属性定义到构造函数里面,公共方法定义到原型对象上。
Object 和 Function
1 | Function.prototype.__proto__ === Object.prototype; |
所有函数的默认原型都是Object
实例。
1 | function fn() {} |
总结:
函数即是函数又是对象,含有__proto__
和 prototype
属性。
__proto__
指向Function.prototype
,Function.prototype
的__proto__
属性又指向了 Object.prototype
;prototype
最终指向Object.prototype
。
如何获得对象非原型链上的属性?
使用hasOwnproperty
方法来判断属性是否属于原型链的属性。