本文已参与「新人创作礼」活动,一起开启掘金创作之路。
JavaScript 中的对象是基于原型的。
什么是原型
JavaScript 中的对象有一个特殊的 [[prototype]] 内置属性,就是对其他对象的引用,这个引用对象被称为此对象的原型。
几乎所有的对象在创建时 [[prototype]] 属性都会被赋予一个非空的值,也就是说几乎所有对象在创建时都有一个与之关联的原型。
JavaScript 中没有类来作为对象的抽象模式,通过原型来实现继承。
prototype 属性
几乎所有对象都有原型,但是只有少数对象有 proto type 属性。正是这些有 prototype 属性的对象为其他对象定义了原型。
prototype 特性
对象的 prototype 特性指的是对象的 [[prototype]] 内置属性。对象的 prototype 特性指定对象从哪里继承属性。
当 prototype 以代码字体出现时,指的是一个普通对象的属性,而不是 prototype 特性。构造函数的 prototype 属性用于指定通过该构造函数创建的对象的 prototype 特性。
function Foo(){}
const foo = new Foo();
Function.prototype.isPrototypeOf(Foo) // true
Foo.prototype.isPrototypeOf(foo) // true
Object.prototype.isPrototypeOf(Foo.prototype) // true
// 改写 prototype 属性
function Bar(){}
Bar.prototype = {a: 1}
const bar = new Bar();
Object.getPrototypeOf(bar) // {a: 1}
Function.prototype.isPrototypeOf(Bar) // true
Bar.prototype.isPrototypeOf(bar) // true
Object.prototype.isPrototypeOf(Bar.prototype) // true
没有原型的对象
Object.prototype 是没有原型的对象,它不继承任何属性。
Object.create(null) 也是没有原型的对象,适合用来存储数据,不用担心受原型链的影响。
检查原型的方法
检查对象和对象的关系
确定一个对象是不是另一个对象的原型(或==原型链==中的一环),可以用 isPrototypeOf(),如下:
const p = {x:1};
const o = Object.create(p);
p.isPrototypeOf(o) // true
Object.prototype.isPrototypeOf(o) // true
Object.prototype.isPrototypeOf(p) // true
检查对象和函数的关系
判断一个对象是不是一个构造函数的实例,可以用 instanceof,instanceof 操作符左侧是对象,右侧是对象类的标识(构造函数)。如下:
const arr = [1,2,3];
arr instanceof Array // true
arr instanceof Object // true 所有数组都是对象
arr instanceof Number // false
instanceof 的工作原理是:为了对 o instanceof f 求值,JavaScript 会对 f.prototype 求值,然后在 o 的原型链上查找这个值。如果找到了,o 是 f 的实例,instanceof 返回 true。否则,o 不是 f 的实例,instanceof 返回 false。
查找和修改对象的原型
查询任何对象的原型,可以用 Object.getPrototypeOf(),如下:
Object.getPrototypeOf({}) // Object.prototype
Object.getPrototypeOf([]) // Array.prototype
Object.getPrototypeOf(()=>{}) // Function.prototype
对象的 prototype 特性在它创建时会被设定,修改对象的原型可以使用 Object.setPrototypeOf() ,如下:
const foo = {x:1};
const bar = {y:2};
Object.setPrototypeOf(foo,bar) // 把 foo 的原型设为 bar
foo.y // 2
对象的 _proto_ 属性暴露了对象的 prototype 特性。在现在 JavaScript 中,_proto_ 是可读可写的,可以(但不应该)代替 Object.getPrototypeOf() 和 Object.setPrototypeOf()。
检查属性
hasOwnProperty() 只会检查属性是否在对象中,不会检查原型链。
in 操作符 会检查属性是否在对象及其原型链中。