JS 原型链
若要建立两个汽车的实体,该如何建立?
Why use OO
减少重複的程式码减少记忆体的使用使实体有关联性类别、物件
类别: 为实体的蓝图、範本 Ex:车子设计图物件: 透过类别建立出来的实体(instance) Ex:车子原型链特性
JS prototype Base 继承方式最上层的原型为物件向上寻找属性、方法的特性继承特性 (不同实体,继承同一属性、方法)类别使用 new关键字 建造出实体小建议
类别 使用大写作为开头 Car静态方法 使用_作为开头 static _add()使用 Object.getPrototypeOf(obj) 取得原型使用 ES6 Class使用 预设参数 & 解构Level 0 (直接建立物件)
直接建立两个物件其缺点: 繁琐、无法统一管理、扩展性差、占用记忆体 const carA = { wheels: 4, pressHorn() { console.log('AAA') }, } const carB = { wheels: 4, pressHorn() { console.log('BBB') }, }
Level 1 (prototype建立蓝图)
利用 JS prototype 建立蓝图使用 new 关键字建立实体缺点: function功能相同,但每次创造实体时都複製一份,占用了不必要的记忆体 // ES6 default parameter const Car = function (brand, sound = '888') { // ES5 预设变数写法 this.brand = brand !== undefined ? name : 'toyota' this.wheels = 4 this.pressHorn = function () { console.log(sound) } // 勿使用此做预设变数,遇到 falsy 会出错 this.test1 = test !! undefined ? test : '123' this.test2 = test || '123' } const carA = new Car('AAA') const carB = new Car('BBB', 'BBB')
Level 2 (在原型上建立共用方法)
将 Function 挂载到蓝图的 prototype利用原型链 向上寻找的特性,实体无该属性、方法即往上寻找可用的属性、方法写于原型仅佔一份记忆体 Car.prototype.pressHorn = function () { console.log(`${this.brand} ${this.sound}`) } // true 表 Function 来自同一个记忆体位置 console.log(carA).pressHorn() === carB.pressHorn())
Level 3 (ES5 Reveal Pattern)
封装内部资料,公开想公开的介面ES5 範例 const Car = function (brand,sound) { this.brand = brand this.wheel = 4 return { brand, } } const test = new Car('A','AAA') console.log(test.wheels) // undefined 不可取得 console.log(test.brand) // 可取得
Level 4 (ES6 Class)
JS 为 prototype base,因此 Class 仅为 prototype的语法糖使用 Class 使语法更精简 class Car { // 写于 constructor的内容,皆会在记忆体创一份新的 // 因此 方法避免写于 constructor 内部 constructor(brand = 'default') { // constructor内容会于实体建立时执行 this.brand = brand this.init() } init() { console.log('init') } pressHorn(){ console.log(`${this.brand} ${this.sound}`) } }
Bonus: 预设参数 & 解构
const User = function ({ name = 'default', age }) { this.name = name // 可预设但可传入修改 this.age = age this.gender = 'male' // 可预设不给用传入的 } // 传入顺序无差,以 Key为基準 let test = new User({ age: 30 }) console.log(test.name, test.gender) // 'default' 'male'
取得原型语法
取得原型1: 双下底线proto (不推荐使用 效能差)取得原型2: Object.getPrototypeOf(obj) (建议使用、IE9+)// ESLint/MDN 不建议使用 __proto__ 取得原型const CarProto = Car.__proto__// 推荐使用 ES5const CarProto = Object.getPrototypeOf(Car)
instanceof 原理 (判断是否有该原型)
判断目标是否在其原型链之下 // 判断 'str' 是否在 String 之下 console.log('str' instanceof String) // false,因为此种表示方法为原始型别,其原型链为 undefined // 使用 new 关键字建立物件 const newStr = new String('newStr') console.log(newStr instanceof String ) console.log(newStr instanceof Object ) // 皆true,String & Object 皆于 newStr 原型链上
参考资料
保哥 物件导向基础
偷米 ES6 Class介绍