JS高级-ES5中实现继承
认识对象的原型
- **JavaScript当中每个对象都有一个特殊的内置属性 [[prototype]],这个特殊的对象可以指向另外一个对象。 **
- 那么这个对象有什么用呢?
- 当我们通过引用对象的属性key来获取一个value时,它会触发 [[Get]]的操作;
- 这个操作会首先检查该对象是否有对应的属性,如果有的话就使用它;
- 如果对象中没有改属性,那么会访问对象[[prototype]]内置属性指向的对象上的属性;
- 那么如果通过字面量直接创建一个对象,这个对象也会有这样的属性吗?如果有,应该如何获取这个属性呢?
- 答案是有的,只要是对象都会有这样的一个内置属性;
- 获取的方式有两种:
- 方式一:通过对象的 proto 属性可以获取到(但是这个是早期浏览器自己添加的,存在一定的兼容性问题);
- 方式二:通过 Object.getPrototypeOf 方法可以获取到;
普通对象的原型
1 | var obj = { |
函数的原型 prototype
函数对象的原型
1 | var obj = {} |
new操作符
- 我们前面讲过new关键字的步骤如下:
- 1.在内存中创建一个新的对象(空对象);
- 2.这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性;
- 那么也就意味着我们通过Person构造函数创建出来的所有对象的[[prototype]]属性都指向Person.prototype:
1 | function Foo() { |
创建对象的内存表现
prototype添加属性
constructor属性
- 事实上原型对象上面是有一个属性的:constructor
- 默认情况下原型上都会添加一个属性叫做constructor,这个constructor指向当前的函数对象
1 | // 非常重要的属性: constructor, 指向Person函数对象 |
重写原型对象
- 如果我们需要在原型上添加过多的属性,通常我们会重写整个原型对象:
- 前面我们说过, 每创建一个函数, 就会同时创建它的prototype对象, 这个对象也会自动获取constructor属性;
- 而我们这里相当于给prototype重新赋值了一个对象, 那么这个新对象的constructor属性, 会指向Object构造函数, 而不是 Person构造函数了
原型对象的constructor
- 如果希望constructor指向Person,那么可以手动添加:
- 上面的方式虽然可以, 但是也会造成constructor的[[Enumerable]]特性被设置了true.
- 默认情况下, 原生的constructor属性是不可枚举的.
- 如果希望解决这个问题, 就可以使用我们前面介绍的Object.defineProperty()函数了.
JavaScript原型链
- 在真正实现继承之前,我们先来理解一个非常重要的概念:原型链。
- 我们知道,从一个对象上获取属性,如果在当前对象中没有获取到就会去它的原型上面获取:
Object的原型
- 那么什么地方是原型链的尽头呢?比如第三个对象是否也是有原型__proto__属性呢?
- 我们会发现它打印的是 [Object: null prototype] {}
- 事实上这个原型就是我们最顶层的原型了
- 从Object直接创建出来的对象的原型都是 [Object: null prototype] {}。
- 那么我们可能会问题: [Object: null prototype] {} 原型有什么特殊吗?
- 特殊一:该对象有原型属性,但是它的原型属性已经指向的是null,也就是已经是顶层原型了;
- 特殊二:该对象上有很多默认的属性和方法;
对象的原型链:
1 | // 1.{}的本质 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 十一的博客!
评论