JS 对象生命周期的秘密

一切皆对象
咱们经常听到JS中“一切皆对象”?有没有问想过这是什么意思?其它语言也有“一切皆对象”之说,如Python 。但是Python中的对象不仅仅是像JS对象这样的存放值和值的容器 。Python中的对象是一个类 。JS中有类似的东西,但JS中的“对象”只是键和值的容器:
【JS 对象生命周期的秘密】var obj = { name: "Tom", age: 34 } 
实际上,JS中的对象是一种“哑”类型,但很多其他实体似乎都是从对象派生出来的 。甚至是数组,在JS中创建一个数组,如下所示:
var arr = [1,2,3,4,5] 
然后用typeof运算符检查类型,会看到一个令人惊讶的结果:
typeof arr"object"看来数组是一种特殊的对象!即使JS中的函数也是对象 。如果你深入挖掘,还有更多,创建一个函数,该函数就会附加一些方法:
var a = function(){ return false; }a.toString()输出:
"function(){ return false; }" 
咱们并没有在函数声明toString方法,所以在底层一定还有东西 。它从何而来?Object有一个名为.toString的方法 。似乎咱们的函数具有相同的Object方法 。
Object.toString() 
这时咱们使用浏览器控制台来查看默认被附加的函数和属性,这个谜团就会变得更加复杂:

JS 对象生命周期的秘密

文章插图
 
谁把这些方法放在函数呢 。JS中的函数是一种特殊的对象,这会不会是个暗示? 再看看上面的图片:我们的函数中有一个名为prototype的奇怪命名属性,这又是什么鬼?
JS中的prototype是一个对象 。它就像一个背包,附着在大多数JS内置对象上 。例如 Object, Function, Array, Date, Error,都有一个“prototype”:
typeof Object.prototype // 'object'typeof Date.prototype // 'object'typeof String.prototype // 'object'typeof Number.prototype // 'object'typeof Array.prototype // 'object'typeof Error.prototype // 'object'注意内置对象有大写字母:
  • String
  • Number
  • Boolean
  • Object
  • Symbol
  • Null
  • Undefined
以下除了Object是类型之外,其它是JS的基本类型 。另一方面,内置对象就像JS类型的镜像,也用作函数 。例如,可以使用String作为函数将数字转换为字符串:
String(34) 
现在回到“prototype” 。prototype是所有公共方法和属性的宿主,从祖先派生的“子”对象可以从使用祖先的方法和属性 。也就是说,给定一个原始 prototype,咱们可以创建新的对象,这些对象将使用一个原型作为公共函数的真实源,不 Look see see 。
假设有个要求创建一个聊天应用程序,有个人物对象 。这个人物可以发送消息,登录时,会收到一个问候 。
根据需求咱们很容易定义这个么一 Person 对象:
var Person = { name: "noname", age: 0, greet: function() { console.log(`Hello ${this.name}`); }};你可能会想知道,为什么这里要使用字面量的方式来声明 Person 对象 。稍后会详细说明,现在该 Person 为“模型” 。通过这个模型,咱们使用 Object.create() 来创建以为这个模型为基础的对象 。
创建和链接对象
JS中对象似乎以某种方式链接在一起,Object.create()说明了这一点,此方法从原始对象开始创建新对象,再来创建一个新Person 对象:
var Person = { name: "noname", age: 0, greet: function() { console.log(`Hello ${this.name}`); }};var Tom = Object.create(Person);现在,Tom 是一个新的对象,但是咱们没有指定任何新的方法或属性,但它仍然可以访问Person中的name和age 属性 。
var Person = { name: "noname", age: 0, greet: function() { console.log(`Hello ${this.name}`); }};var Tom = Object.create(Person);var tomAge = Tom.age;var tomName = Tom.name;console.log(`${tomAge} ${tomName}`);// Output: 0 noname现在,可以从一个共同的祖先开始创建新的person 。但奇怪的是,新对象仍然与原始对象保持连接,这不是一个大问题,因为“子”对象可以自定义属性和方法
var Person = { name: "noname", age: 0, greet: function() { console.log(`Hello ${this.name}`); }};var Tom = Object.create(Person);Tom.age = 34;Tom.name = "Tom";var tomAge = Tom.age;var tomName = Tom.name;console.log(`${tomAge} ${tomName}`);// Output: 34 Tom这种方式被称为“屏蔽”原始属性 。还有另一种将属性传递给新对象的方法 。Object.create将另一个对象作为第二个参数,可以在其中为新对象指定键和值:


推荐阅读