聊聊javascipt oop

JavaScriptOOP

object Literals

const circle = {
    radius: 1,
    location: {
        x:1,
        y:1
    }
    draw: function(){

    }
};

Factory

function createCircle(radius){
    return {
        radius,
        draw: function(){
            console.log('draw');
        }
    };
}

const circle = createCircle(1);
circle.draw();

constructor

function Circle(radius){
    this.radius = radius;
    this.draw = function(){
        //do sth
    }
}
const another = new Circle(1);
//1.create a object{} 
//2.this refers to the object instead of referring to window(global object)
//if we do const another = Circle(1);
//this refers to window 

let x= {}
// let x = new Object();
//new String();  '', "" new Boolean(); new Number(); // 1, 2, 3

values VS reference types

let x = 10;
let y = x;

y = 20; // x = 10 y=20

// primitives are copied by their value, Objects are copied by their reference.
let x = { value: 10 }
let y = x;
x.value = 20; // x { value: 20} y { value: 20}

Value Types Reference type
number Object
string Function
Boolean Array
Symbol
undefined
null
let number = 10;

function increase(number){
    number++;
}
increase(number); // number 10

let obj = { value: 10 }
function increase(obj){
    obj.value++;
}
increase(obj); //{ value: 11 }

Add and delete properties

function createCircle(radius){
    return {
        radius,
        draw: function(){
            console.log('draw');
        }
    };
}

const circle = createCircle(1);
circle.location = { x: 1 };
circle['location'] = { x: 1 };
// const propertyName = 'center location';
// circle.propertyName doesn't work, circle[propertyName] works
delete circle.location;
delete circle['location'];

enumerate properties

function Circle(radius){
    this.radius = radius;
    this.draw = function(){
        //do sth
    }
}
const another = new Circle(10);

for (let key in circle) {
    if (typeof cirlce[key] !== 'function')
        console.log(key, circle[key]);
}

const keys = Object.keys(circle); //["radius", "draw"]
if ('radius' in circle)
  console.log("Circle has a radius");

abstration hide details show essentials

function Circle(radius) {
    this.radius = radius;
    let computeOptimumLocation = function(factor){
    //closure stays
    }
    let defaultLocation = { x: 0, y: 0 }; //change this to let to be private

    this.getDefaultLocation = function() {
        return defaultLocation;
    }

    this.draw = function(){
        let x, y; //scope is temporary....finish after executing within draw
        computeOptimumLocation(0.1);

    };

}

const circle = new Circle(10);
circle.draw();

Getters and Setters

function Circle(radius) {
    this.radius = radius;

    let defaultLocation = { x: 0, y: 0 }; //private cannot access outside 

    this.getDefaultLocation = function() { //accessible
        return defaultLocation;
    }

    this.draw = function(){
    };

    Object.defineProperty(this, 'defaultLocation', {
        get: function(){ //READONLY
            return defaultLocation;
        },
        set: function(value) {
            if (!value.x || !value.y) 
                throw new Error('Invalid location.');
            defaultLocation = value;
        }
    });

}

const circle = new Circle(10);
circle.getDefaultLocation();//method 1 to access private var
circle.defaultLocation//method 2 to access private var READONLY

function Stopwatch() {
    let start, end, duration, running = 0;

    this.start = function () {
        if (running)
            throw new Error('Stop watch has already started.'); 
        running = true;
        start = new Date();
    }
    this.stop = function () {
        if (!running)
            throw new Error("Stop watch hasn't started."); 
        running = false;
        end = new Date();
        const seconds = (end.getTime() - start.getTime()) / 1000;
        duration += seconds;
    }

    this.reset = function () {
        start = null;
        end = null;
        duration = 0;
        running = false;
    }

    Object.defineProperty(this, 'duration', {
        get: function(){ //READONLY
            return duration; 
        }
    });
}

Inheritance

classical | prototype

Object.getPrototypeOf(myObj);

property descriptor

let person = { name: 'Mosh' };
for (let key in person)
    console.log(key); //name
Object.keys(person); // ["name"]
let objectBase = Object.getPrototypeOf(person); // myObj.__proto__(parent of myObj)
let descriptor = Object.getOwnPropertyDescriptor(objectBase, 'toString');
console.log(descriptor);
// {value: f, writable: true, enumerable: false, configurable: true}
// configurable: true enumerable: false value: f toString() writable: true __proto__: Object

objectBase.defineProperty(person, 'name', {
    writable: false, // cannot delete name 
    enumerable: true,
    configurable: false
});

delete person.name;

ProtoType vs Instance memeber

Circle.prototype === c1.proto

function Cirlce(radius) {
    //instance member
    this.radius = radius;

    this.move = function () {
        this.draw(); // prototype and instance member inherite each other
        console.log('move');
    }
}
Cirlce.prototype.draw = function() {
    //this.move();
    console.log("draw");
}

Cirlce.prototype.toString = function () {
    return 'Circle with radius ' + this.radius;
}
const c1 = new Cirlce(1);
c1.move() // draw move
const c2 = new Cirlce(1);

console.log(Object.keys(c1)); //["radius", "move"] only show instance
for (let key in c1) console.log(key); // radius, move, draw also show prototype
c1.hasOwnProperty('radius') // true ONLY INSTANCE MEMBER
c1.hasOwnProperty('draw') // false

// don't modify objects you don't own

create your own prototypes inheritance

| Shape | Circle |
| | --- |
| --- | radius |
| proto | proto |
| duplicate | draw |
| constructor | constructor |
| shape | cirlce |
| proto | proto |
| object | object |

function Shape() {
} 

Shape.prototype.duplicate = function() {
    console.log('duplicate');
}

function Circle(radius) {
    this.radius = radius;
} 

Circle.prototype.draw = function() {
    console.log('draw');
}

const s = new Shape(); // s -> shapeBase(Shape.prototype) -> objectBase
const c = new Circle(1);

circle inheritate shape

Circle.prototype = Object.create(Shape.prototype); 
Shape Circle
radius
proto proto:shape
duplicate draw
constructor
shape
proto proto
object duplicate
constructor
shape
proto
Object

Resetting the constructor: reset the prototype, reset the constructor

new Circle.prototype.constructor(1);
new Circle(1);
Circle.prototype.constructor() = Circle(); 

Calling the super constructor

function Shape(color) {
this.color = color;
} 

Shape.prototype.duplicate = function() {
    console.log('duplicate');
}

function Circle(radius, color) {
    Shape.call(this, color);
    this.radius = radius;
} 

Circle.prototype.draw = function() {
    console.log('draw');
}

const s = new Shape(); // s -> shapeBase(Shape.prototype) -> objectBase
const c = new Circle(1);

Intermediate function Inheritance

function extend(Child,Parent){
    Child.prototyp.constructor = Object.create(Parent.prototype);
    Child.prototype.constructor = Child;
}

extend(Circle, Shape);

Method overwriting

function extend(Child,Parent){
    Child.prototype = Object.create(Parent.prototype);
    Child.prototype.constructor = Child;
}
function Shape() {
} 
Shape.prototype.duplicate = function() {
    console.log('duplicate');
}
function Circle() {
}
extend(Circle, Shape);
Circle.prototype.duplicate = function() {
  Shape.prototype.duplicate.call(this); //without this line it would only call 'duplicate cirlce'
  console.log('duplicate cirlce');
}
c.duplicate() //first call: 'duplicate' second call: 'duplicate cirlce'

Polymorphism

function Shape(){}
Shape.prototype.duplicate = function(){ console.log('duplicate') };
function Circle(){};
extend(Circle, Shape);
Circle.prototype.duplicate = function(){ console.log('duplicate circle') };
function Square(){};
extend(Square, Shape);
Square.prototype.duplicate = function(){ console.log('duplicate Square') };

const shapes = [ new Circle(), new Square()];
for (let shape of shapes)
    shape.duplicate();//'duplicate circle' 'duplicate Square'

Mixins

function mixin(target, ...sources){
    Object.assign(target, ...sources);
}
const canEat = {
    eat: function(){
        this.hunger--;
        console.log('eating');
    }
};
const canWalk = {
    walk: function(){
        console.log('walking');
    }
};
const canSwim = {
    swim: function(){
        console.log('Swimming');
    }
};
function Person(){}
Object.assign({Person.prototype}, canEat, canWalk); 
const person = new Person();
console.log(person);//__proto__: eat:f walk:f constructor: f Person() __proto__:Object
function Goldfish(){}
mixin(Goldfish.prototype, canEat, canSwim); const goldfish = new Goldfish();

prototype inheritance

function HtmlElement(){
  this.click = function(){
    console.log('click');
  }
}

HtmlElement.prototype.focus = function(){ 
}

function HtmlSelectElement(items = []){
  this.items = items;

  this.addItem = function(item){
    this.items.push(item);
  }

  this.removeItem = function(item){
    this.items.splice(this.items.indexOf(item), 1);
  }
}
HtmlSelectElement.prototype = new HtmlElement(); 
object.create(HtmlElement.prototype); // this gets u an empty HtmlSelectElement
//HtmlSelectElement -> addItem, items, removeItem, __proto__:__proto__, focus:f(), constructor HtmlElement->__proto__:Object
HtmlSelectElement.prototype.constructor = HtmlSelectElement;

polymorphsim excercise

function HTMLSelectElement(){
  this.render = function(arr){
    return `<select>
      ${this.items.map(item =>
        `<option>
        ${item}
        </option>`).join('')}
      </select>`;
  }
}

function HtmlImageElement(src){
  this.src = src;
  this.render() = function(){
   return `<img src="${this.src}" />`;
  }
}
HtmlImageElement.prototype = new HtmlElement(); 
HtmlImageElement.prototype.constructor = HtmlImageElement;

ES6 Classes classes are functions

function Circle(radius){
    this.radius = radius;
    this.draw = function(){
        //do sth
    }
}

class Circle {
  constructor(radius){
    this.radius = radius;
  }

  draw(){
    console.log('draw');
  }
}

const c = new Circle(1); // Circle->radius,__proto__->constructor, draw, __proto__

hoisting

sayHello()// this works sayGoodbye // this doesn't
//functional hoisting
function sayHello(){}
// functional expression
const sayGoodbye = function(){}

//function can be hoisted, expression cannot //class cannot be hoisted

const c = new Circle(1);
//class declaration
class Circle{}
//class expression
const Square = class {  
};

static method

class Circle {
  constructor(radius){
    this.radius = radius;
  }

  draw(){
    console.log('draw');
  }

  static parse(str) {
    const radius = JSON.parse(str).radius;
    return new Circle(radius);
  }
}

const circle = Circle.parse('{"radius":1}');
console.log(circle);//Circle {radius:1}=>radius:1,__proto__:Object

'use strict';//use strict mode to prevent modify global objects

const Circle = function(){
  this.draw = function(){
    console.log(this);
  }
};

const c = new Circle();
//method call
c.draw();
const draw = c.draw;
//functional call
draw(); // global object

ES6 private member using Symbol

Symbol() === Symbol() //false

const _radius = Symbol();
const _draw = Symbol();
class Circle {
  constructor (radius){
    //this.radius = radius;
    //this['radius'] = radius;
    this[_radius] = radius;
  }
  [_draw](){

  }
}

const c = new Circle(1); //Circle->Symbol(),__proto__

//const key = Object.getOwnPropertySymbols(c)[0];
console.log(c[key]);//1

WeakMap {key:value}

const _radius = new WeakMap(); // key are weak, value can be edited
const _move = new WeakMap();
class Circle {
  constructor(radius) {
    _radius.set(this, radius);//(key:object, value) this makes Circle empty -> __proto__
   // _move.set(this, function(){
   //   console.log('move', this);// undefined this, c.draw() move undefined 
   // });
    _move.set(this, () => {
      console.log('move', this);// move -> Circle {}, draw
    });

  }

  draw() {
    console.log(_radius.get(this));//
    _move.get(this)(); // read private member 
    console.log('draw')
  }
}

const c = new Circle(1);

getters and setters

const _radius = new WeakMap();

class Circle {
  constructor (radius) {
    _radius.set(this, radius);
  }
  get radius() {
    return _radius.get(this);
  }
  set radius(value) {
    if (value <= 0) throw new Error('Invalid Radius');
    _radius.set(this, value);
  }
}

const c = new Circle(1);

inheritance

class Shape {
    constructor(color){
        this.color = color;
        }
    move() {
        console.log('move');
        }
}
class Circle extends Shape {
    constructor(color, radius){
    super(color);
    this.radius = radius;
    }

    draw() {
        console.log('draw');
        }
}
const c = new Circle(); // Circle=>proto:Shape->constructor:Circle, draw->proto:constructor  shape,move->__proto__

method overwriting

class Shape {
    move() {
        console.log('move');
        }
}
class Circle extends Shape {
    move() {
        super.move();
        console.log('circle move');
        }
}
const c = new Circle();//move,circle move

stack

//implementationt detail
const _items = new WeakMap();
//public interface
class Stack {
    constructor() {
     _items.set(this, []);
    }

    push(obj){
    _items.get(this).push(obj);
    }

    pop() {
        if (_items.get(this).length === 0)
            throw new error('Stack is empty');
        return _items.get(this).pop();
    }

    peek() {
       if (_items.get(this).length === 0)
            throw new error('Stack is empty');
       return _items.get(this)[_items.get(this).length - 1);
   }

   get count() {
        return _items.get(this).length;
        }
}

modules

export

module.exports.Circle = Circle;

require

const Circle = require('./circle');
const c = new Circle(10);

ES6 modules

export

export class xxx {
}

import

import {Circle} from './circle.js';

index.html

<script type="module" src="index.js"></script>

tools

transpiler: translate + compiler Bundler: webpack combines .js into one file

Babel npm init --yes (creates pakage.json)npm i babel-cli@6.26.0 babel-core@6.26.0 babel-preset-env@1.6.1 --save-dev command line interface / core of babel / let const => plugin package.json "script":{ "babel": "babel --preset3 env index.js -o build/index.js" }, $npm run babel

webpack

npm i -g webpack-cli@2.0.14webpack-cli init + package.json "script":{ "build": "webpack -w" }, $npm run build

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容