创建对象
JavaScript 创建对象的方法:1. 使用构造函数 2. 使用字面量 3. Object.create()
使用构造函数
使用构造函数作为对象的模板生成实例对象,函数内用 this 关键字代表生成的对象实例。就是操作一个空对象,将其”构造”为需要的样子。
new 的过程:
- 创建一个新的空对象;
- 新对象的
__proto__
指向构造函数的prototype
; - 新对象赋值给内部的 this 并执行;
- 返回新对象 this;
使用 new 命令,构造函数内部的 this 代表了新生成的实例对象,this.price 表示实例对象有一个 price 属性,值是 10。
1 | //执行构造函数,返回一个实例对象。 |
不使用 new 命令,直接调用构造函数,构造函数就变成了普通函数,并不会生成实例对象。
1 | var Apple = function (){ |
使用字面量
1 | // getPrototypeOf() 返回指定对象的原型 |
使用字面量创建对象时,实际上就调用了这些构造函数生成实例对象 (如Object、Array、Function等)。
使用 Object.create()
create 是 Object 构造函数的一个方法,该方法接受一个对象作为参数,然后以它为原型,返回一个实例对象。该实例对象完全继承参数对象的属性和方法:1
2
3
4var A = {name:'jack'}
var B = Object.create(A)
B.__proto__ === A // true
B.name // jack
Object.create 方法生成的新对象,动态继承了原型。在原型上添加或修改任何方法,会立刻反映在新对象之上。
1 | A.age = 24 |
原型链
每个构造函数都有一个 prototype
属性指向一个对象,用来存放共有属性的地址,每个实例对象都有一个 __proto__
属性指向它的构造函数的 prototype
属性。
每个原型对象都有一个 constructor
属性,指向相关联的构造函数,所以构造函数和构造函数的 prototype
是可以相互指向的。1
Array.__proto__ === Function.prototype //true
构造函数的原型对象的所有属性和方法,都能被实例对象共享,如果属性和方法定义在构造函数的 prototype
上,那么所有实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系。
1 | let arr = [1,2,3,4] |
Array.prototype
继承了Object.prototype
的属性和方法。arr 继承了Array.prototype
的属性和方法,同时也继承了Object.prototype
的属性和方法。(所有对象都有valueOf
和toString
方法的原因是从Object.prototype
继承的)Object.prototype
的原型是null,没有任何属性和方法,也没有自己的原型。所以原型链的尽头就是null。- 所有对象都有一个
__proto__
属性指向一个原型(prototype),从实例对象到原型,再到原型的原型…… 这样就形成了一个原型链(prototype chain)。
总结:
- Object 是所有对象的爸爸,所有对象都可以通过
__proto__
找到它; - Function 是所有函数的爸爸,所有函数都可以通过
__proto__
找到它; - Function.prototype 和 Object.prototype 是两个特殊的对象,他们由引擎来创建;
- 除了以上两个特殊对象,其他对象都是通过构造函数 new 出来的;
- 函数的 prototype 是一个对象,也就是原型;
- 对象的
__proto__
指向原型,__proto__
将对象和原型连接起来组成了原型链; - 关于继承,实例对象可以访问这根链条上的属性和方法,其实数组都继承于 Array.prototype,函数都继承于 Function.prototype;(判断是否为直接生成的实例,用 constructor 比用 instanceof 更严谨)
构造函数、原型、实例、原型链之间的关系:
1 | //Object 的构造函数是 Function。 |
Reference:
https://wangdoc.com/javascript/oop/index.html
https://github.com/KieSun/Dream/issues/2