# 一、创建对象和原型链

# 1 面向对象的三大特性

⚡ 30 秒速记

  • 封装:把状态收进对象内部只暴露方法,JS 里靠闭包、WeakMap# 私有字段实现,下划线前缀只是约定
  • 继承:把公共能力放在原型上共享,class extends 的本质是把子类原型接到父类原型上
  • 多态:同一个调用点因实例不同走不同实现,JS 不需要额外语法,属性查找沿原型链先找到谁就用谁
  • 三条在 JS 里全部落在原型链上,讲清「原型链怎么查找」比背定义值钱
  • 加分点:JS 没有真正的类,class 只是构造函数的语法糖,主动点破这句能显出理解深度

JS 的三大特性都是原型链的应用,不是语言内建的类机制 —— 按「封装靠作用域、继承靠原型指向、多态靠查找顺序」三层讲。

  • 封装
  • 继承
  • 多态

# 1.1 原型链的知识

原型链是面向对象的基础,是非常重要的部分。有以下几种知识:

  • 创建对象有几种方法
  • 原型、构造函数、实例、原型链
  • instanceof的原理
  • new 运算符

💬 面试官追问

  • 同事说 JS 没有真正的私有属性,加个下划线前缀就当私有了,你在 review 里会拦吗?

    会。下划线只是口头约定,外部照样能读能改。真要私有就用 # 私有字段,或者用 WeakMap 把状态存在实例外面。库代码尤其要用真私有 —— 用户一旦依赖了你的内部字段,这个字段你就再也改不动了。

  • 既然 class 只是语法糖,老项目里的构造函数直接改成 class 有风险吗?

    有三处行为差异:class 声明有暂时性死区不会提升、方法默认不可枚举所以 for...in 遍历不到、不加 new 调用直接抛 TypeError。老代码如果有遍历原型方法做序列化,或者有意无意地省了 new,迁移后当场就炸。

# 2 创建对象有几种方法

⚡ 30 秒速记

  • 字面量 {}new Object() 等价,原型都是 Object.prototype
  • 构造函数 new Foo():实例属性各自一份,原型上的方法所有实例共享
  • Object.create(p):直接指定原型为 p,不经过构造函数,寄生组合继承靠的就是它
  • Object.create(null):造出没有原型的纯净字典,拿用户输入当 key 也不会撞上 toString
  • class 是构造函数的语法糖;工厂函数则每次返回全新对象、不共享原型
  • 区分标准只有一条:新对象的原型指向谁,用 Object.getPrototypeOf 一验就知道

五种写法的差别不在语法,而在「新对象的原型指向谁」 —— 按「字面量 → 构造函数 → Object.createclass → 工厂函数」顺着原型指向讲。

# 2.1 方式一:字面量

    var obj11 = {name: 'smyh'};
    var obj12 = new Object(name: `smyh`); //内置对象(内置的构造函数)

上面的两种写法,效果是一样的。因为,第一种写法,obj11会指向Object

webapp
公众号
开发者导航
切换夜间模式
点击侧边栏上一篇
点击侧边栏下一篇
折叠侧边栏
收起全部