Skip to content

Latest commit

 

History

History
481 lines (347 loc) · 8.58 KB

12.2.objects.md

File metadata and controls

481 lines (347 loc) · 8.58 KB
title
Fyrirlestur 12.2 – Hlutir

Fyrirlestur 12.2 – Hlutir

Vefforritun 1 — TÖL107G

Ólafur Sverrir Kjartansson, osk@hi.is


Hlutir og hjúpun

  • Objects & encapsulation
  • Ein af aðal hugmyndum hlutbundinnar forritunar er að skipta forritum upp og láta hvern hluta bera ábyrgð á eigin stöðu
  • Hjúpum virkni og flækjustig, vinnum með í gegnum interface

Methods

  • Method er fall á hlut
  • Hvað ef við viljum nálgast gögn á hlutnum úr falli?
  • Notum this

this

  • this hagar sér öðruvísi í JavaScript en í öðrum málum
  • Skilgreinist af því hvernig kallað er í fallið
  • Utan hluta er this global hluturinn, þ.e. þar sem allt er geymt (í browser window)

function foo() {
  console.log(this);
}

const bar = {
  foo() {
    console.log(this);
  },
};

console.log(this); // window
foo(); // window
bar.foo(); // {foo: f}

const rabbit = {};
rabbit.speak = (line) => {
  console.log(`The rabbit says '${line}'`);
};

rabbit.speak('I’m alive.');
// → The rabbit says 'I’m alive.'

Apply & call

  • Leyfir okkur að kalla í föll með ákveðnu this
  • apply – köllum í fall með gefnu this og fylki af arguments
  • call – köllum í fall með gefnu this og lista af arguments

function speak(line) {
  console.log(
    `${this.type} rabbit says ${line}`
  );
}
const oldRabbit = { type: 'old', speak };
const hungryRabbit = { type: 'hungry', speak };

oldRabbit.speak('Oh my');
// old rabbit says Oh my
hungryRabbit.speak('I could use a carrot');
// hungry rabbit says I could use a carrot

function speak(line) {
  console.log(
    `${this.type} rabbit says ${line}`
  );
}
const oldRabbit = { type: 'old' };

speak.apply(oldRabbit, ['Oh my']);
// old rabbit says Oh my
speak.call({ type: 'hungry' }, 'Yum');
// hungry rabbit says Yum

Bind

  • Leyfir okkur að festa, binda, this fyrir föll
  • Kemur okkur ekki á óvart hvað this er
  • Getum líka bundið argument...

Bind – dæmi

function speak(line) {
  console.log(
    `${this.type} rabbit says ${line}`
  );
}
const blueRabbit = { type: 'blue' };
const bound = speak.bind(blueRabbit);
bound('hi');
// blue rabbit says hi
speak.bind(blueRabbit, 'bye')();
// blue rabbit says bye

Arrow föll

  • Arrow föll eru öðruvísi—endurskilgreina ekki this
  • this er skilgreint eins og það var skilgreint í scope kringum fall

function normalize() {
  console.log(
    this.coords.map(
      n => n / this.length
    )
  );
}

const o = { coords: [0, 2, 3], length: 5 };

normalize.call(o);
// → [0, 0.4, 0.6]

function normalize() {
  function inner(n) {
    return n / this.length;
  }
  console.log(this.coords.map(inner));
}

const o = { coords: [0, 2, 3], length: 5 };

normalize.call(o);
// → [NaN, Infinity, Infinity]

Prótótýpur

  • Flestir hlutir hafa prótótýpu, hlutur sem geymir fleiri properties
  • Ef við biðjum um property á hlut sem er ekki skilgreint á hlut er leitað á prótótýpu hans

  • Í grunninn höfum við Object
    • Eða nánar tiltekið Object.prototype
  • Object.getPrototypeOf() skilar hvaða prótótýpu gildi hefur

const empty = {};
console.log(empty.toString);
// → function toString() { … }
console.log(empty.toString());
// → [object Object]

Aðrar prótótýpur

  • Aðrir hlutir hafa aðrar prótótýpur
    • [] hefur Array.prototype
    • Föll hafa Function.prototype
  • Þessar prótótýpur hafa sínar eigin prótótýpur!
    • Mynda prótótýpu keðju

const emptyProto = Object.getPrototypeOf({});
console.log(
  emptyProto === Object.prototype
);
// → true
console.log(
  Object.getPrototypeOf(Object.prototype)
);
// → null

const funcProto = Object.getPrototypeOf(
  Math.max
);

console.log(
  funcProto === Function.prototype
);
// → true
console.log(
  Object.getPrototypeOf(funcProto) ===
    Object.prototype
);
// → true

const arrayProto = Object.getPrototypeOf([]);

console.log(
  arrayProto === Array.prototype
);
// → true

Prótótýpu keðjan

  • Hlutir fá eigindi frá prótótýpunni en eigindi á hlutnum hafa aldrei áhrif á keðjuna
    • Getum ekki skrifað yfir hluti á prótótýpu
  • Að setja eigindi á hlut setur það alltaf á honum sjálfum

  • Ef við biðjum um eigindi á hlut er reglan:
    • Ef það er á hlut fáum við það
    • Ef ekki förum við upp prótótýpu keðjuna og leitum þar
    • Ef finnst hvergi er undefined skilað

Hlutir með ákveðna prótótýpu

  • Object.create() býr til hlut með ákveðinni prótótýpu
  • Leið til að hópa saman föllum
  • Prótótýpan geymir sameiginlegu föllin

const protoRabbit = {
  speak(line) {
    console.log(
      `${this.type} rabbit says '${line}'`
    );
  }
};
const killer = Object.create(protoRabbit);
killer.type = 'killer';
killer.speak('SKREEEE!');
// → killer rabbit says 'SKREEEE!'

Klasar (classes)

  • Í JavaScript höfum við ekki klasa eins og í klassískum hlutbundnum málum
  • Notum prótótýpu til að erfa frá öðrum hlutum

  • Í klassískum erfðum
    • Hlutir eru tilvik af klösum
    • Klasar erfa frá öðrum klösum
  • Með prótótýpum
    • Engir klasar
    • Hlutir erfa frá öðrum hlutum

Smiðir og new

  • Í JavaScript eru smiðir föll, skýrð með stórum staf
  • Þegar við notum new og tilgreinum fall búum við til nýjan hlut þar sem this bendir á hlutinn
  • Skilar sjálfkrafa this sem hlut vegna new ef engu er skilað
  • Bætum við prótótýpu til að bæta við sameiginlegum föllum

function Rabbit(type) {
  this.type = type;
}
Rabbit.prototype.speak = function (line) {
  console.log(
    `The ${this.type} rabbit says '${line}'`
  );
};
const weirdRabbit = new Rabbit('weird');
console.log(weirdRabbit);
// Rabbit {type: "weird"}
weirdRabbit.speak('🐰');
// The weird rabbit says '🐰'

Yfirskrifuð eigindi

  • Að setja eigindi á hlut setur það alltaf á honum sjálfum
  • Getum nýtt til að yfirskrifa eigindi frá prótótýpu
    • T.d. toString() til að skila sértæku gildi fyrir okkar hlut

Rabbit.prototype.teeth = 'small';
const killerRabbit = new Rabbit('killer');
console.log(killerRabbit.teeth);
// → small
killerRabbit.teeth = 'long, sharp, bloody';
console.log(killerRabbit.teeth);
// → long, sharp, and bloody

Erfðir á rabbits


function Rabbit(type) {
  this.type = type;
}

const fooRabbit = new Rabbit('foo');
console.log(fooRabbit.toString());
// "[object Object]"

Rabbit.prototype.toString = function () {
  return `Rabbit of type ${this.type}`;
};

console.log(fooRabbit.toString());
// "Rabbit of type foo"

Classes

  • Í ECMAScript 6 er class skilgreint
  • Syntactic sugar til að herma eftir klassískum OO hlutum með prótótýpum
  • extends, constructor, super, static og getters og setters

class Rabbit {
  constructor(type) {
    this.type = type;
  }
  speak(line) {
    console.log(
      `${this.type} rabbit says '${line}'`
    );
  }
  toString() {
    return `Rabbit of type ${this.type}`;
  }
}

const killerRabbit = new Rabbit('killer');

class Foo {
  constructor(name) {
    this._name = name;
  }

  hi() { return 'hi!'; }

  static bar() { return 1; }

  get name() { return this._name; }

  set name(value) { this._name = value; }
}

const foo = new Foo('Asdf');
foo.hi(); // "hi!"
foo.name = 'bar';
foo.name; // "bar"

Foo.bar(); // 1