# 一、创建对象和原型链
# 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也不会撞上toStringclass是构造函数的语法糖;工厂函数则每次返回全新对象、不共享原型- 区分标准只有一条:新对象的原型指向谁,用
Object.getPrototypeOf一验就知道
五种写法的差别不在语法,而在「新对象的原型指向谁」 —— 按「字面量 → 构造函数 → Object.create → class → 工厂函数」顺着原型指向讲。
# 2.1 方式一:字面量
var obj11 = {name: 'smyh'};
var obj12 = new Object(name: `smyh`); //内置对象(内置的构造函数)
上面的两种写法,效果是一样的。因为,第一种写法,
obj11会指向Object。