JS 的三座大山

  1. this
  2. 原型
  3. AJAX
  • JS 要有很多东西,这些东西都挂在 window 上,浏览器就提供了 window

image.png

对象是 { } 的完整写法 Array 是 [ ] 的完整写法 Function 是小写 function 的完整写法

  • 都挂在 window 上是为了方便在任何地方直接用

内存图

image.png
image.png

  • 指向和引用的意思是保存了它的地址

关于 window

  • window 变量window 对象是两个东西
  • window 变量是一个容器,存放 window 对象的地址
  • window 对象Heap 里的一坨数据
  • 例:var x = window ,那么这个 x 就指向了 window 对象,window 变量可以消失了

同理:

  • consoleconsole 对象不是同一个东西
  • ObjectObject 函数对象不是同一个东西
  • 前者是内存地址,后者是一坨数据


原型链

目前只关心小写对象的隐藏属性,不关心大写对象的隐藏属性,避免绕晕。

下列的代码为什么不报错 ? 为什么可以运行 ?

  1. var obj = {}
  2. obj.toString()

图解1:
image.png

  • obj 有一个隐藏属性
  • 隐藏属性存储了 Object.prototype 对象的地址
  • obj.toString() 发现 obj 上没有 toString
  • 就去隐藏属性对应的对象里找
  • 于是就找到了 Object.prototype.toString

obj 和obj2 有什么联系?

  1. var obj = {}
  2. obj.toString()
  3. var obj2 = {}
  4. obj2.toString()

相同点:

  • 都可以调用 **.toString()**

不同点:

  • 地址不同 **obj !== obj2**
  • 可以拥有不同的属性

问:如果 obj 改变了 toString ,那新创建的 obj2toString 是否会被改变?
答:不会

  • 一层是可以篡改的,两层是没有简单的办法篡改的,除非通过图示中的 ‘fuke’(也就是 __proto__ 来篡改)。

图解2:
image.png

1. 什么是原型?

**XXX.prototype** 储存了 **XXX** 对象的共同属性,这就是原型

2. 什么情况下有 prototype 属性?

答:如果第一个字母是大写就有 prototyp 属性。例如:Object、Array等。

3. 原型的作用:

  • 原型可以无需重复声明共有属性
  • 省代码,省内存

    4. 隐藏属性叫什么?

  • **__proto__**

    5. 隐藏属性的作用:

  • 每个对象都有一个隐藏属性,指向原型(对象)

  • 如果没有这个隐藏属性,那么 obj 都不知道自己的共有属性在哪

    6. Object 作为对象是否具有隐藏属性?

  • Object 也有隐藏属性,它的隐藏属性指向哪里涉及到一个 JS 的哲学问题,暂不讨论

  • 只需知道如果一个对象的首字母是大写的,它就会拥有一个 prototype 属性,然后就不用关心它的隐藏属性
  • 只有对象首字母为小写的时候再关心它的隐藏属性
  • 需要先把小写的隐藏属性搞清楚,再去理解大写的,不然容易绕晕。

    **Object****object** 的区别是什么?

  • Object 是一个全局函数,可以用来生成对象,var obj = new Object() ,可以简写成 var obj = {};

  • 而 object 什么也不是,除非我声明一个 var object

    7. **prototype****__proto__** 区别是什么?

  • 都存着原型的地址

  • 只不过 **prototype** 都挂在函数上
  • **__proto__** 挂在每个新生成的对象上

问:下面的代码为什么不报错?为什么可以运行?

  1. var arr = [1,2,3]
  2. arr.join('-')

图解:
image.png

  • arr 有一个隐藏属性
  • 隐藏属性储存了 Array.prototype 对象的地址
  • arr.join() 发现 arr 上没有 join ,就去隐藏属性对应的对象里找,于是找到了 Array.prototype.join


8. 在不同的数组里的共有属性是否能篡改?

在不同的数组里去篡改共有属性是无法篡改的,因为改的时候读不到共有属性,只有在读的时候才能读到共有属性。

9. 关于原型(共有属性),正确的有

  • Object.prototype 保存了一个对象的地址,这个对象包含了所有普通对象的共有属性,叫做对象的原型
  • Array.prototype 保存了一个对象的地址,这个对象包含了是所有数组的共有属性,叫做数组的原型
  • Function.prototype 保存了一个对象的地址,这个对象包含了是所有函数的共有属性,叫做函数的原型
  • 每个对象都有一个隐藏属性,用来保存其原型的地址,这个隐藏属性的名字叫做 proto

原型和共有属性的区别?

  • 原型是对象
  • 共有属性是属性
  • 原型包含了所有共有属性(共有属性依附在原型这个对象上) | 红圈为原型
    蓝线画的是一个个共有属性 | image.png | | —- | —- |

原型

每个对象都有原型

  • 原型里存着对象的共有属性
  • 比如 obj 的原型就是一个对象
  • obj.__proto__ 存着这个对象的地址
  • 这个对象里有 toString / constructor / valueOf 等属性

    对象的原型也是对象

  • 所以对象的原型也有原型

  • obj = {} 的原型即为所有对象的原型
  • 这个原型包含所有对象的共有属性,是对象的根
  • 这个原型也有原型,是 null

JS 重要且唯一的公式:原型公式

对象.proto === 其构造函数.prototype

Object.prototype 与原型的关系?

  • Object.prototype 存了原型的地址
  • 结论:
    • 你是谁构造的,你的原型就是谁的 prototype 属性对应的对象

参考资料:《protoprototype存在的意义是什么》方方

属性和属性的值是两个概念
image.png

问:

  • let square = new Square(5)

    1. square 的原型(square.__proto__ 的值)是什么?
    • Square.prototype
  • Object.prototype 是哪个函数构造出来的?

    • 不知道,它没有父母
  • Object.prototype 的原型是什么?
    • 根对象没有原型
  • Object.prototype.proto
    • null

参考文章

proto 和 prototype 存在的意义是什么?