初学者跪着学JavaScript Day19 : 原型毕露(上)

一日客语:中文:拜托你 客语:bai togˋnˇ 掰偷 三声n

物件都有原型,当自己属性找不到时就会往原型找,然後一直找一直找除非找到,要不就找到null

物件:物件的原型继承某个“一般物件”: 使用方式 Object.setPrototypeOf

物件: 物件的来源是“建构函式”: 使用方式 new constructor


物件的原型继承某个“一般物件”

平常使用的物件方式

//像是雨伞学院,每人都有不同能力
const wendy = { fly: 30 };
const ann = { run: 50 };
const nick = { swimming: 100 };
console.log('fly' in wendy); //true
console.log('run' in wendy); //false

有个神奇想法
我想要ann的跑步能力!!!

把ann设为wendy的原型prototype
prototype可以在浏览器下看wendy物件[[prototype]],这里观察一下

要如何把ann变成我的原型?
使用Object.setPrototypeOf(继承者物件,原型物件)

Hint:使用in可以找属性

方式:
1.wendy原型设ann:

Object.setPrototypeOf(wendy, ann);
console.log('run' in wendy); //true`

我想要得到谁力量就把那人设成我的原型

2.那ann原型设nick呢?ann就会得到nick的力量

3.然後wendy也会继承ann和nick的属性,这样wendy会飞、跑、游泳

Object.setPrototypeOf(wendy, ann);
console.log('run' in wendy); //true
//把ann的原型设为nick,想要游泳能力
Object.setPrototypeOf(ann, nick);
//身为ann继承者wendy也具有游泳的能力
console.log('swimming' in wendy);//true

物件的来源是“建构函式”

  • function 也有原型物件(function(){}的prototype)
  • function创建出来的物件,物件的[[prototype]]会设为function(){}的prototype
    假设:Cat建构子,nini是实例
    也就是说Cat.prototype == nini.__proto__

最容易搞混的地方:
在浏览器观察
建构函式有prototype属性 =>Cat.prototype
nini(实例)有[[prototype]]属性(但无法选取,只能靠其他方式) =>nini.__proto__

看到没~就是这样建立了不可告人的关系
还要注意建构子也有可能是别物件的实例
所以也会有prototype(会当某物件的爸)和[[prototype]](也可能是别人的儿子)


想法上:

在function Cat的原型(物件)加一个eat方法

Cat()

function Cat() {  }
Cat.prototype.eat = function () {
    return 'eat';
}
let b = Cat();//一般function
console.log(b); //undefined

但这样只是呼叫function

根据刚刚说的 function 建出来的物件的原型也会是function prtototype

所以要思考如何才能让function 建出物件? 使用new 运算子

new + function 会建立新物件:new Cat()

此function会是 constructor (建构器)按照惯例要大写
所以cat()=>Cat()

function Cat() {}

Cat.prototype.eat = function () {
    return 'eat';
};

const a = new Cat();
console.log(a)//{}
console.log(a.eat());//eat

a是经由function 建立出的物件,这个物件的原型有eat方法

问题来了要如何在新物件上加上自带属性?? 可以使用this

new 运算子和this的关系

mdn:

The new operator lets developers create an instance of a user-defined object type or of one of the built-in object types that has a constructor function

new运算子根据内建或自己定义的constructor function 创建instance(实例)

  • 函式呼叫会将this传进function内

    资料参考:忍者开发者技巧探秘第二版
function Cat(name) {
    this.name = name;
    
    
    this.sleep = function () {
        return 'sleeping';//这写法不太好,晚点解释
    };
}

let cat1 = new Cat('kiki');
let cat2 = new Cat('niki');
let cat3 = new Cat('nini');

console.log('cat1', cat1);
//cat1 Cat { name: 'kiki', sleep: [Function (anonymous)] }
console.log('cat2', cat2);
//cat2 Cat { name: 'niki', sleep: [Function (anonymous)] }
console.log('cat3', cat3);
//cat3 Cat { name: 'nini', sleep: [Function (anonymous)] }

第三步:书上会说新的空物件会被设定为函式背景空间

this指的是新建立的物件

Cat()function 没有回传(return)物件会回传新建立的物件

所以记忆体会拨出一块空间放新物件

函式原型有constructor属性

函式原型有constructor属性会指向(reference)到原来的函式


重点笔记:

cat1 增加属性可以三种方式

1.自带自身的属性:使用this

2.增加原型的属性

3.增加实例的属性

function Cat() {
    this.name = 'kitty';
    //自带自身的属性
    this.sleep = function () {
        //自带自身的属性
        return 'sleeping';
    };
}

let cat1 = new Cat();
Cat.prototype.fruit = 'apple'; //增加原型的属性
cat1.lay = 'lay'; //增加实例属性

console.log(cat1.fruit); //apple
console.log(cat1.sleep()); //sleeping
console.log(cat1.lay); //lay


看prototype(原型)方式:

  • Object.__proto__
  • Object.getPrototypeOf()
function Cat(name) {
    this.name = name;
    this.sleep = function () {
        return 'sleeping';
    };
}

let cat1 = new Cat('kiki');
Cat.prototype.eat = 'apple';
Cat.prototype.eyes = 2;

console.log(Object.getPrototypeOf(cat1)); 
//{ eat: 'apple', eyes: 2 }
console.log(cat1.__proto__); 
//{ eat: 'apple', eyes: 2 }
console.log(cat1); 
//Cat { name: 'kiki', sleep: [Function (anonymous)] }

Cat原型(prototype)的constructor属性指向Function

function Cat(name) {
    this.name = name;
    this.sleep = function () {
        return 'sleeping';
    };
}

let cat1 = new Cat('kiki');
Cat.prototype.eat = 'apple';
Cat.prototype.eyes = 2;
console.log(Object.getPrototypeOf(cat1).constructor);
//[Function: Cat]
console.log(cat1.__proto__.constructor);
//[Function: Cat]

当prototype和instance的方法同名一样会先找到哪一个?

function内this.eat vs Cat.prototype.eat

会先选择instance(实例)优先於prototype(原型)

function Cat(name) {
    this.name = name;
    this.sleep = function () {
        return 'sleeping';
    };
    this.eat = 'apple';//自身
}

Cat.prototype.eat = 'banana';//原型
Cat.prototype.eyes = 2;
let cat1 = new Cat('kiki');

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

回到这样写法不好的原因

function Cat(name) {
    this.name = name;
    
    this.sleep = function () {
        return 'sleeping';//这写法不太好,晚点解释
    };
}

let cat1 = new Cat('kiki');
let cat2 = new Cat('niki');
let cat3 = new Cat('nini');

console.log('cat1', cat1);
//cat1 Cat { name: 'kiki', sleep: [Function (anonymous)] }
console.log('cat2', cat2);
//cat2 Cat { name: 'niki', sleep: [Function (anonymous)] }
console.log('cat3', cat3);
//cat3 Cat { name: 'nini', sleep: [Function (anonymous)] }

cat1、cat2、cat3都有各自sleep function,若当物件创立n个会有n个sleep function
在程序会希望相同逻辑会可以共用,尽可能省记忆体空间,因此加在Cat的原型下创建物件使用它的sleep function(只要一个)


原型我也还在学习,这是目前我理解的样子
真是累的不要不要的QQ

(主要阅读忍者开发技巧探秘第二版书籍)
资料来源:
忍者开发技巧探秘第二版
mdn


<<:  Day 19 MMU 与 TLB

>>:  Day18:WS 串接 Client & Server

[Day3] OpenAPI

什麽是API API是Application Programming Interface的缩写。 A...

D16 第八周 (回忆篇)

这礼拜进度开始落後,在写第七周作业的 todo list,自己後来才发现事件代理的用法,所以後面又重...

【Day29】漫谈 AI 在音乐上其他的优秀作品

超强的 AI 作曲 在 2020 年的时候 NVIDIA 在 YT 上发表了这支影片,里头使用到的音...

onnx - 用 netron 查看 onnx 模型版本参考笔记

onnx - 用 netron 查看 onnx 模型版本参考笔记 参考资料 参考资料如下: netr...

Day 8:架设 Prometheus (0)

昨天简单介绍过 Prometheus 了,那麽今天我们就自己架一个来玩看看吧。尝试任何一个新工具的第...