JS 对象生命周期的秘密( 三 )


  • 创建一个空对象
  • 将空对象的proto指向构造函数的prototype
  • 使用空对象作为上下文的调用构造函数
  • function Person(name, age) {
  • this.name = name;
  • this.age = age;
  • }
根据上面描述的,new Person("Valentino") 做了:
  • 创建一个空对象:var obj = {}
  • 将空对象的proto__`指向构造函数的 prototype:`obj.__proto = Person().prototype
  • 使用空对象作为上下文调用构造函数:Person.call(obj)
检查原型链
检查JS对象之间的原型链接有很多种方法 。例如,Object.getPrototypeOf是一个返回任何给定对象原型的方法 。考虑以下代码:
var Person = { name: "noname", age: 0, greet: function() { console.log(`Hello ${this.name}`); }};var Tom = Object.create(Person);检查Person是否是Tom的原型:
var tomPrototype = Object.getPrototypeOf(Tom);console.log(tomPrototype === Person);// Output: true当然,如果使用构造函数调用构造对象,Object.getPrototypeOf也可以工作 。但是应该检查原型对象,而不是构造函数本身:
function Person(name, age) { this.name = name; this.age = age;}Person.prototype.greet = function() { console.log("Hello " + this.name);};var me = new Person("Valentino");var mePrototype = Object.getPrototypeOf(me);console.log(mePrototype === Person.prototype);// Output: true除了Object.getPrototypeOf之外,还有另一个方法isPrototypeOf 。该方法用于测试一个对象是否存在于另一个对象的原型链上,如下所示,检查 me 是否在 Person.prototype 上:
Person.prototype.isPrototypeOf(me) && console.log('Yes I am!') 
instanceof运算符也可以用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置 。老实说,这个名字有点误导,因为JS中没有“实例” 。在真正的面向对象语言中,实例是从类创建的新对象 。请考虑Python中的示例 。咱们有一个名为Person的类,咱们从该类创建一个名为“tom”的新实例:
class Person(): def __init__(self, age, name): self.age = age; self.name = name; def __str__(self): return f'{self.name}'tom = Person(34, 'Tom')注意,在Python中没有new关键字 。现在,咱们可以使用isinstance方法检查tom是否是Person的实例
isinstance(tom, Person)// Output: TrueTom也是Python中“object”的一个实例,下面的代码也返回true:
isinstance(tom, object)// Output: True根据isinstance文档,“如果对象参数是类参数的实例,或者是它的(直接、间接或虚拟)子类的实例,则返回true” 。咱们在这里讨论的是类 。现在让咱们看看instanceof做了什么 。咱们将从JS中的Person函数开始创建tom(因为没有真正的类)
function Person(name, age) { this.name = name; this.age = age;}Person.prototype.greet = function() { console.log(`Hello ${this.name}`);};var tom = new Person(34, "Tom");使用isinstance方法检查tom是否是Person和 Object 的实例
if (tom instanceof Object) { console.log("Yes I am!");}if (tom instanceof Person) { console.log("Yes I am!");}因此,可以得出结论:JS对象的原型总是连接到直接的“父对象”和Object.prototype 。没有像Python或Java这样的类 。JS是由对象组成,那么什么是原型链呢?如果你注意的话,咱们提到过几次“原型链” 。JS对象可以访问代码中其他地方定义的方法,这看起来很神奇 。再次考虑下面的例子:
var Person = { name: "noname", age: 0, greet: function() { console.log(`Hello ${this.name}`); }};var Tom = Object.create(Person);Tom.greet();即使该方法不直接存在于“Tom”对象上,Tom也可以访问greet() 。
这是JS的一个内在特征,它从另一种称为Self的语言中借用了原型系统 。当访问greet()时,JS引擎会检查该方法是否可直接在Tom上使用 。如果不是,搜索将继续向上链接,直到找到该方法 。
“链”是Tom连接的原型对象的层次结构 。在我们的例子中,Tom是Person类型的对象,因此Tom的原型连接到Person.prototype 。而Person.prototype是Object类型的对象,因此共享相同的Object.prototype原型 。如果在Person.prototype上没有greet(),则搜索将继续向上链接,直到到达Object.prototype 。这就是咱们所说的“原型链” 。
保护对象不受操纵
大多数情况下,JS 对象“可扩展”是必要的,这样咱们可以向对象添加新属性 。但有些情况下,我们希望对象不受进一步操纵 。考虑一个简单的对象:
var superImportantObject = { property1: "some string", property2: "some other string"};


推荐阅读