携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情
前言
大家好呀,我是L同学。在上篇文章面向对象(二)中,我们学习了面向对象的相关知识点,包括构造函数和实例对象的关系、构造函数存在的问题、什么是原型等相关知识点。在本篇文章中,我们将继续学习面向对象的相关知识点,包括原型与原型链、内置标准库与包装对象等相关知识点。
原型与原型链
构造函数、对象、原型三者之间的关系可以用下图表示。
构造函数的 prototype 属性,就是由这个构造函数 new 出来的所有实例对象的 原型对象。所有对象都有原型对象。
function Cat(name, color) {
this.name = name;
}
var cat1 = new Cat('猫');
console.log(cat1.__proto__.__proto__.__proto__);
而原型对象中的属性和方法,都可以被实例对象直接使用。每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索顺序是这样子的:
- 搜索首先从对象实例本身开始
- 如果在实例中找到了具有给定名字的属性,则返回该属性的值
- 如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性
- 如果在原型对象中找到了这个属性,则返回该属性的值
- 如果还是找不到,就到原型的原型去找,依次类推。
- 如果直到最顶层的Object.prototype还是找不到,则返回undefined。
而这正是多个对象实例共享原型所保存的属性和方法的基本原理。
对象的属性和方法,有可能是定义在自身内,也有可能是定义在它的原型对象上。由于原型本身也是对象,又有自己的原型,所以形成了一条可向上追溯的链条,叫 原型链(prototype chain)。需要注意的是,不要在原型上形成多层链式查找,非常浪费资源。
内置标准库与包装对象
在内置标准对象中,对象是 JavaScript 语言最主要的数据类型,三种原始类型的值——数值、字符串、布尔值——在一定条件下,也会自动转为对象,也就是原始类型的“包装对象”。
所谓“包装对象”,就是分别与数值、字符串、布尔值相对应的Number、String、Boolean三个原生对象。这三个原生对象可以把原始类型的值变成(包装成)对象。
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属性。调用结束后,这个临时对象就会被销毁。这就叫原始类型与实例对象的自动转换。