06-1 | 读JavaScript 高程

2020-05-25  本文已影响0人  cemcoe

接上篇

知识点:
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 来组织代码,下篇来看继承。

上一篇 下一篇

猜你喜欢

热点阅读