初学者跪着学JavaScript Day22 : 我要原型继承,constructor又不走丢

一日客语:中文:晚上 客语:暗晡am buˊ  

function Plant() {}
function Apple() {}
Apple.prototype.shape = 'circle';

Apple.prototype = new Plant();//现在Apple的prototype是放 Plant的实例
const myapple = new Apple();
console.log(myapple.constructor);//[Function: Plant]

使用原型继承会让constructor指向Plant function,使myapple的constructor不是Apple function,从程序码的写法来说明明是建构函式Apple所建立的实例,但显示的建构子会是plant function。
原本constructor可以判断由哪一个函式建立,现在却不是预期的样子

如果使用原型继承又要让constructor是Apple?


Object.defineProperty()

语法:Object.defineProperty(obj, prop, descriptor)

对物件设定新属性或修改物件属性回传设定好的物件

Object.defineProperty(定义的物件, 属性,属性描述子)

属性描述子(property descriptor)是什麽?

物件内的每一个属性都有property descriptor

  1. configurable
  2. enumerable
  3. value
  4. writable
  5. get
  6. set
property descriptor 说明
configurable 物件的property 是否可以被修改/删除
enumerable 物件的property是否被for/in 回圈Object.keys()
writable 物件的property的值是否能被改变
value 设定属性值
get 定义取值getter function 可以取得属性值,不能和value/writable一起设定
set 定义设值setter function 可以设定属性指派的值,不能和value/writable一起设定

所以descriptor也是一个物件

property descriptor的 writable

这个属性的值可以修改吗
true:可以修改
false:不可以修改

const apple = {};

Object.defineProperty(apple, 'color', {
    value: 'red',
    writable: false,
});

apple.color = 'gold';
console.log(apple.color);//red
const apple = {};

Object.defineProperty(apple, 'color', {
    value: 'red',
    writable: true,
});

apple.color = 'gold';
console.log(apple.color);//gold

property descriptor的enumerable

是否可以被for/in迭代列出

目标:设定apple的shape属性,是不可以被for/in迭代列出
作法:把property descriptor的enumerable设成false

let apple = {};
Object.defineProperty(apple, 'color', { value: 'red', enumerable: true });
Object.defineProperty(apple, 'shape', { value: 'circle', enumerable: false });
Object.defineProperty(apple, 'size', { value: 'small', enumerable: true });
Object.defineProperty(apple, 'price', { value: 10000, enumerable: true });

for (let i in apple) {
    console.log(i);
}
//color
//size
//price

property descriptor的getter

取值时,启动get,return 出fruit[0]//apple出去

const map = {
    fruit: ['apple', 'orange', 'banana'],
    get eat() {
        return this.fruit[0];
    },
    set eat(value) {
        this.fruit[0] = value;
    },
};

console.log(map.eat);//apple


property descriptor的setter

赋值时,启动set,会把value(water)赋值到fruit[0]

const map = {
    fruit: ['apple', 'orange', 'banana'],
    get eat() {
        return this.fruit[0];
    },
    set eat(value) {
        this.fruit[0] = value;
    },
};

map.eat = 'water';

//现在fruit: ['water', 'orange', 'banana']

使用这个方式解决constructor

function Go() {}
function Run() {}
Go.prototype.school = 'sleep';
Run.prototype = new Go();
const student = new Run();

console.log(student.constructor);//[Function: Go]

解决方式:就是在property descriptor 让Apple.prototype的constructor设定为 Apple,且不让他被改写也让他不要出现在for-in回圈

function Plant() {}
function Apple() {}
Apple.prototype.shape = 'circle';

Apple.prototype = new Plant();
const myapple = new Apple();
Object.defineProperty(Apple.prototype, 'constructor', {
    value: Apple,
    enumerable: false,
    writable: false,
});
console.log(myapple.constructor); //Function: Apple]

这样方式既可以继承,constructor也是指向当初建立的函式

学完一整套原型链~赞

资料参考:
忍者开发技巧探秘第二版
mdn


<<:  [Day 22] 节庆活动 api分析&页面设计

>>:  Day 23 用户资料数据下载定义规划实作

GitHub Action 实作持续交付 - 常见代理程序架构与部署至 IIS

透过前一篇文章的介绍,读者应该了解现今的云端服务相当方便,许多持续交付的功能已经写成 Action,...

Day22 切版笔记- 互动图文卡片

运用到的观念: 利用vertical-align: middle;调整图片预设多余的空间 使用po...

【设计+切版30天实作】|Day6 - 设计出背景上又有背景的吸睛小广告

设计大纲 上一个区块设计了使用者的「痛点」,因此接下来的区块想要做一个「平台的小广告」,让使用者了解...

Day4:梯度下降法(Gradient descent)

  梯度下降法经常被使用为优化学习的一种方式,寻找局部最佳解(至於为何是局部,之後会提到),想像有个...

【Day2】声音的一些基本介绍

声音这东西实在是太自然了,所以我们很少去思考这东西的本质到底是什麽 简单的来复习一下声音是什麽,你...