接上篇
知识点:
1.构造函数原型实例三者是怎样的一个关系?
2.如何确定一个属性是在对象本身还是在原型身上?
3.原型方法创建对象的缺点?
4.较为合理的创建对象的方案是原型加构造函数?
5.ES6中的class是怎么一回事?
1.构造函数原型实例三者是怎样的一个关系?
每个函数都有一个属性叫做 prototype 指向该函数的原型对象,而该原型对象也有一个属性叫做 constructor 指回了函数,两者形成了一个圈。
在采用原型创造对象时涉及三个东西,构造函数,原型对象,实例即要创建的对象。问题的关键是搞明白这三者的关系。
前面是函数和原型对象的关系,函数通过ptototype 指向原型对象,原型对象通过constructor指向函数,这就是两者的关系。
下面我们将实例添加进来。
首先是构造函数和实例的关系,实例通过构造函数创建,实例有一个属性[[prototype]] 指向构造函数的原型对象,但实例和构造函数间并无此项直接的联系。
三者的关系是这样的:彼此间通过指针连接,函数和原型是互相指的关系,实例和原型是单向指向的关系,函数和实例间没有直接的指向关系。
2.如何确定一个属性是在对象本身还是在原型身上?
先来看两个 API,hasOwnPrototype() 方法 和 in 操作符。
hasOwnPrototype() 方法只在属性存在实例本身时返回 true,当属性只存在在原型上时返回false。而 in 操作符,不管属性定义在哪里,只要有就返回 true。两者配合就可以确定属性定义的位置。
比如 in 操作符为 false 时,属性在原型和实例本身都不存在,这是就不需要 hasOwnPrototype() 出马了。而当 in 操作符为 true 且 hasOwnPrototype() 方法为 false 时,该属性存在于原型中。
3.原型方法创建对象的缺点?
对于属性中的引用类型一处更改全部都会变动,每处都会受到影响。
4.较为合理的创建对象的方案是原型加构造函数?
构造函数和原型可以互相补充,实例属性的定义交给构造函数,而实例通用的属性和方法交给原型定义。这样就可以求同存异,节约内存资源。
书中来提到了动态原型模式,寄生构造函数模式以及稳妥构造函数模式,有兴趣的可以看一下。
构造函数和原型模式结合的方式对于大部分场景已经可以解决了。
// 构造函数
function Person(name, age) {
this.name = name
this.age = age
}
// 原型
Person.prototype = {
constructor: Person
// 防止指向乱掉
sayName() {
console.log(this.name)
}
}
// 创建实例对象
const p1 = new Person('cemcoe', 18)
// p1对象相当于
// p1 = {
// name: 'cemcoe',
// age: 10,
// sayName() {
// console.log('cemcoe')
// }
// }
5.ES6中的class是怎么一回事?
首先明确一点,class只是一个语法糖。
将上面的代码使用 class 进行改写如下:
class Person {
// 构造函数
constructor(name, age) {
this.name = name
this.age = age
}
// 原型
sayName() {
console.log(this.name)
}
}
// 使用时没有变化
// 创建实例对象
const p1 = new Person('cemcoe', 18)
可以看到 ES6 的 class 用起来代码结构更加的清晰,对函数的定义被大括号包裹着,不会显得很乱。
对创建对象方法的探索暂时告一段落,推荐使用 ES6 中的 class 来组织代码,下篇来看继承。
网友评论