面向对象(三)

83 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情

前言

大家好呀,我是L同学。在上篇文章面向对象(二)中,我们学习了面向对象的相关知识点,包括构造函数和实例对象的关系、构造函数存在的问题、什么是原型等相关知识点。在本篇文章中,我们将继续学习面向对象的相关知识点,包括原型与原型链、内置标准库与包装对象等相关知识点。

原型与原型链

构造函数、对象、原型三者之间的关系可以用下图表示。

image.png

构造函数的 prototype 属性,就是由这个构造函数 new 出来的所有实例对象的 原型对象。所有对象都有原型对象。

function Cat(name, color) {
    this.name = name;
 }

var cat1 = new Cat('猫');

console.log(cat1.__proto__.__proto__.__proto__);

而原型对象中的属性和方法,都可以被实例对象直接使用。每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索顺序是这样子的:

  1. 搜索首先从对象实例本身开始
  2. 如果在实例中找到了具有给定名字的属性,则返回该属性的值
  3. 如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性
  4. 如果在原型对象中找到了这个属性,则返回该属性的值
  5. 如果还是找不到,就到原型的原型去找,依次类推。
  6. 如果直到最顶层的Object.prototype还是找不到,则返回undefined。

而这正是多个对象实例共享原型所保存的属性和方法的基本原理。

对象的属性和方法,有可能是定义在自身内,也有可能是定义在它的原型对象上。由于原型本身也是对象,又有自己的原型,所以形成了一条可向上追溯的链条,叫 原型链(prototype chain)。需要注意的是,不要在原型上形成多层链式查找,非常浪费资源。

内置标准库与包装对象

在内置标准对象中,对象是 JavaScript 语言最主要的数据类型,三种原始类型的值——数值、字符串、布尔值——在一定条件下,也会自动转为对象,也就是原始类型的“包装对象”。

所谓“包装对象”,就是分别与数值、字符串、布尔值相对应的NumberStringBoolean三个原生对象。这三个原生对象可以把原始类型的值变成(包装成)对象。

var v1 = new Number(123);
var v2 = new String('abc');
var v3 = new Boolean(true);

typeof v1 // "object"
typeof v2 // "object"
typeof v3 // "object"

v1 === 123 // false
v2 === 'abc' // false
v3 === true // false

包装对象的最大目的,首先是使得 JavaScript 的对象涵盖所有的值,其次使得原始类型的值可以方便地调用某些方法。原始类型的值,可以自动当作对象调用,即调用各种对象的方法和参数。这时,JavaScript 引擎会自动将原始类型的值转为包装对象实例,在使用后立刻销毁实例。比如,字符串可以调用length属性,返回字符串的长度。

'abc'.length // 3

上面代码中,abc是一个字符串,本身不是对象,不能调用length属性。JavaScript 引擎自动将其转为包装对象,在这个对象上调用length属性。调用结束后,这个临时对象就会被销毁。这就叫原始类型与实例对象的自动转换。