在浏览器的控制台中,尝试创建一个对象字面量
jsconst myObject = {
city: "Madrid",
greet() {
console.log(`Greetings from ${this.city}`);
},
};
myObject.greet(); // Greetings from Madrid
这是一个包含一个数据属性 city 和一个方法 greet() 的对象。如果你在控制台中输入对象的名称,后面跟着一个点,比如 myObject.,那么控制台将弹出一个包含此对象所有可用属性的列表。你会看到除了 city 和 greet 之外,还有很多其他属性!
__defineGetter__
__defineSetter__
__lookupGetter__
__lookupSetter__
__proto__
city
constructor
greet
hasOwnProperty
isPrototypeOf
propertyIsEnumerable
toLocaleString
toString
valueOf
尝试访问其中一个
jsmyObject.toString(); // "[object Object]"
它起作用了(即使不清楚 toString() 是做什么的)。
这些额外的属性是什么,它们来自哪里?
JavaScript 中的每个对象都具有一个内置属性,称为其 **原型**。原型本身是一个对象,因此原型将有自己的原型,从而形成所谓的 **原型链**。当我们到达原型链的末尾,即原型自身的原型为 null 时,链条就会结束。
**注意:** 指向对象原型的对象属性**不**叫 prototype。它的名称没有标准,但实际上所有浏览器都使用 __proto__。访问对象原型的标准方法是 Object.getPrototypeOf() 方法。
当你尝试访问对象的属性时:如果在对象本身中找不到属性,则会在原型中搜索该属性。如果仍然找不到属性,则会在原型的原型中搜索,依此类推,直到找到该属性,或者到达链条的末尾,在这种情况下将返回 undefined。
所以当我们调用 myObject.toString() 时,浏览器
在 myObject 中查找 toString
在那里找不到,因此在 myObject 的原型对象中查找 toString
在那里找到它并调用它。
myObject 的原型是什么?为了找到答案,我们可以使用 Object.getPrototypeOf() 函数
jsObject.getPrototypeOf(myObject); // Object { }
这是一个名为 Object.prototype 的对象,它是所有对象默认具有的最基本原型。Object.prototype 的原型是 null,因此它位于原型链的末尾
对象的原型并不总是 Object.prototype。试试这个
jsconst myDate = new Date();
let object = myDate;
do {
object = Object.getPrototypeOf(object);
console.log(object);
} while (object);
// Date.prototype
// Object { }
// null
这段代码创建了一个 Date 对象,然后沿着原型链向上遍历,记录原型。它向我们展示了 myDate 的原型是一个 Date.prototype 对象,而该对象的原型是 Object.prototype。
事实上,当你调用熟悉的方法,比如 myDate2.getTime() 时,你是在调用 Date.prototype 上定义的方法。