创建对象的几种方法
字面量创建对象
var o1 = {name: 'o1'}
使用 Object 构造函数创建对象
var o2 = new Object({ name: 'o2' })
使用显式构造函数创建
是用 Object.create 创建一个指定原型的对象
var Obj = function (name) { this.name = name }
var o3 = new Obj('o3')
原型链
var proto = { name: 'o4' }
var o4 = Object.create(proto)
[图片上传失败...(image-f192bc-1516980030996)]
原型链描述
1. 从一个实例对象向上找构造这个实例相关联的对象,
2. 再从从这个相关联的对象继续向上找创建这个对象相关联的对象,
3. 以此类推一直到 Object.prototype (null) 终止.
原型链通过什么连接和寻找
通过构造函数 prototype 和 实例对象的 proto 进行寻找
原型对象 prototype 有什么特点
构造函数的 prototype 由此构造函数创建的多个实例共同使用的对象
instanceof 的原理
[图片上传失败...(image-be8bfc-1516980030996)]
判断实例对象: proto 和构造函数: prototype 两者的引用是否是同一个原型的引用地址 (比如 Object.prototype)
在原型链上的构造函数都会返回 true
面向对象
类与实例
new 操作符使用
var P = function (name) {
this.name = name
}
class P {
constructor (name) {
this.name = name
}
}
const p = new P('name')
new 操作符做了什么
// 使用 new 操作符直接创建实例
var p1 = new Person('laoyang', '22', 'coding')
// 不使用 new 操作符
var p2 = new Object() // p2 创建成为一个对象 这时 p2 的原型是 Object
Person.call(p2, 'xiaoyang', '2', 'test') // Person 构造函数在 p2 对象的环境内执行 这时 p2 已经是一个具有 Person 属性的实例了,但原型是 Object
p2.__proto__ = Object.create(Person.prototype) // 最后创建一个原型为 Person.prototype 的 p2.__proto__,让 p2 的原型为 Person.prototype
创建一个空对象,它继承自构造函数 Person.prototype
构造函数 Person 被执行,执行时相应的参数会被传入,同时上下文 this 会被指定为这个新实例
如果构造函数 Person 返回了一个对象,那么这个对象会取代整个 new 出来的结果,如果构造函数没有返回对象,那么 new 出来的结果为创建的对象
继承有几种方式
var new = function(func) {
var o = Object.create(func.prototype)
var k = function.call(o)
if (typeof k === 'object') {
return k
} else {
return o
}
}
var obj = new(P)
obj instanceof P // true
obj.__proto__.constructor === P // true
借助构造函数实现继承
缺点: Parent 的原型对象 prototype 无法继承
function Parent () {
this.name = 'parent'
}
Parent.prototype.fn = function () {}
function Child () {
Parent.call(this)
this.type = 'child'
}
借助原型链实现继承
优点: 解决了 Parent 原型对象的继承
function Parent () {
this.name = 'parent'
this.arr = [1,2,3]
}
function Child () {
this.type = 'child'
}
Child.prototype = new Parent()
缺点: 由 Child 创建的多个实例对象共享父类的引用类型
前两种的组合方式
var c1 = new Child()
var c2 = new Child()
c1.arr.push(4)
c2.arr // [1, 2, 3, 4]
优点: 不仅实现了父类 prototype 的继承,也通过 Parent.call(this) 创建了各实例独自的 arr 复杂类型
function Parent () {
this.name = 'parent'
this.arr = [1, 2, 3, 4]
}
function Child () {
Parent.call(this)
this.type = 'child'
}
Child.prototype = new Parent()
缺点: 不够优雅,可以优化
组合方式优化 1
优点: Child 不仅继承了 Parent 的 prototype,而且实现优雅
function Parent () {
this.name = 'parent'
this.arr = [1, 2, 3]
}
function Child () {
Parent.call(this)
this.type = 'child'
}
Child.prototype = Parent.prototype
缺点: Child 创建的实例 constructor 指向是 Parent, 而且修改了 Parent.prototype 会同时改变 Child.prototype 和由 Child 创建实例的__proto__
组合方式优化 2
优点: 不仅完成了继承,同时把 Child.prototype.constructor 指向自己,使得每个实例的__proto__.constructor 都指向 Child 构造函数,更规范.使用 Object.create(proto) 方法创建了一个原型对象为 Parent.prototype 但是又和 Parent.prototype 彻底分离的纯净对象,与 Child.prototype 两者互不影响.
function Parent () {
this.name = 'parent'
this.arr = [1, 2, 3]
}
function Child () {
Parent.call(this)
this.type = 'child'
}
Child.prototype = Object.create(Parent.prototype) // 创建一个纯净的对象
Child.prototype.constructor = Child // 把 Child 原型的 constructor 指向自己
来源: http://www.jianshu.com/p/90a68b6239dd