JavaScript 面向对象的编程 (Code with mosh学习笔记)

JavaScript OOP

Getting Start - 1- What is OOP

  • 面向对象的编程是一种编程范例
  • 围绕对象而不是函数
  • 一些OOP语言
    • C#
    • Java
    • Ruby
    • Python
    • JavaScript

Getting Start - 2- Four Pillars of OOP

OOP的4个概念:

  • 封装
    • 使用封装重新组合相关的变量和函数
    • 减少复杂性
    • 增加代码的可复用性
  • 抽象
    • 通过抽象隐藏细节和复杂性
    • 隔离了代码更改的影响
  • 继承
    • 继承可以消除冗余代码
  • 多态
    • 多态可以避免写出复杂的选择性代码

Getting Start - 3- Setting Up the Development Environment

  • 软件:vscode
  • 插件:Live Server

Objects - 1- Introduction

在这里插入图片描述

Objects - 2- Object Literals

const circle = {
    radius: 1,
    location: {
        x: 1,
        y: 1
    },
    draw: function() {
        console.log('draw');
    }
};

circle.draw();

Objects - 3- Factories

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

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

Objects - 4- Constructors

function Circle(radius) {
    this.radius = radius;
    this.draw = function() {
        console.log('draw');
    }
}
const another = new Circle(1);

Objects - 5- Constructor Property

每个对象都有一个构造函数属性 (.constructor),该属性引用了用来创建这个对象的构造函数

Objects - 7- Value vs Reference Types

在这里插入图片描述

Objects - 8- Adding or Removing Properties

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

const circle = new Circle(1);

circle.location = { x: 1 };

const pName = 'center location';
circle[pName] = { x: 2};

delete circle['location'];

console.log(circle);

Objects - 9- Enumerating Properties

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

const circle = new Circle(1);

for (let key in circle) {
    console.log(key, circle[key]);
}

Objects - 11- Private Properties and Methods

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

    this.defaultLocation = { x:0, y:0 };

    this.computeOptimumLocation = function(factor) {
        // ...
    };

    this.draw = function() {
        this.computeOptimumLocation(0.1);
        
        console.log('draw');
    };
}

const circle = new Circle(10);
function Circle(radius) {
    this.radius = radius;
    // 将过程变量和函数设为本地变量和本地函数,而不是对象的属性与方法(抽象)
    let defaultLocation = { x:0, y:0 };

    let computeOptimumLocation = function(factor) {
        // ...
    };

    this.draw = function() {
        computeOptimumLocation(0.1);

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

const circle = new Circle(10);

Objects - 12- Getters and Setters

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

    let defaultLocation = { x:0, y:0 };

    let computeOptimumLocation = function(factor) {
        // ...
    };

    this.draw = function() {
        computeOptimumLocation(0.1);
        console.log('draw');
    };

    // 通过defineProperty的方式,设置getter和setter
    Object.defineProperty(this, 'defaultLocation', {
        get: function() {
            return defaultLocation;
        },
        set: function(value) {
            if (!value.x || !value.y)
                throw new Error('Invalid location.');
            defaultLocation = value;    
        }
    });
}

const circle = new Circle(10);
circle.defaultLocation = {x:10,y:100};
console.log(circle.defaultLocation);

Objects - 14- Exercise- Stopwatch

function StopWatch() {
    let startTime, endTime, running, duration = 0;

    this.start = function() {
        if (running)
            throw new Error('Already running')
        
        running = true;
        startTime = new Date();
    };

    this.stop = function() {
        if (!running)
            throw new Error('Not running')

        running = false;
        endTime = new Date();
    };

    this.reset = function() {
        running = false;
        startTime = 0;
        endTime = 0;
        duration = 0;
    };

    Object.defineProperty(this, 'duration', {
        get: function() {
            return parseInt(endTime - startTime) / 1000;
        }
    });
}

sw = new StopWatch();

Prototypes - 1- Inheritance

在这里插入图片描述

Prototypes - 2- Prototypes and Prototypical Inheritance

在这里插入图片描述

  • 当访问一个对象的成员时,js引擎会沿着原型链路一直找,直到找到为止
  • 原型也是一般的对象
  • js中创建的对象都直接或间接的继承自元对象
  • 在内存中只有一个元对象的实例
let x = {};
let y = {};

console.log(Object.getPrototypeOf(x) === Object.getPrototypeOf(y));

Prototypes - 3- Multilevel Inheritance

在这里插入图片描述

  • 如果对象由给定的构造函数创造,那么它们拥有同一个原型

Prototypes - 4- Property Descriptors

let person = { name: 'Mosh' };

Object.defineProperty(person, 'name', {
    // 将name改为不可写入,不可配置
    writable: false,
    enumerable: true,
    configurable: false
});

person.name = 'John';
delete person.name;
console.log(person);

Prototypes - 5- Constructor Prototypes

对象. __ proto __ = 构造函数.prototype

// myObi.__proto__ (parent of myObj)
// Constructor.prototype (parent of myObj)
let obj = {};
console.log(obj.__proto__);
console.log(Object.prototype);

Prototypes - 6- Prototype vs Instance Members

function Circle(radius) {
    // Instance members
    this.radius = radius;

    this.move = function() {
        this.draw();
        console.log('move');
    }
}

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

// 就近原则
Circle.prototype.toString = function() {
    return 'Circle with radius '+ this.radius;
}

const c1 = new Circle(1);
c1.move();
console.log(c1.toString());

Prototypes - 7- Iterating Instance and Prototype Members

  • Object.keys 只返回实例的成员
  • for in 循环返回所有的成员
function Circle(radius) {
    // Instance members
    this.radius = radius;

    this.move = function() {
        this.draw();
        console.log('move');
    }
}

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

// 就近原则
Circle.prototype.toString = function() {
    return 'Circle with radius '+ this.radius;
}

const c1 = new Circle(1);

// Return instance members
console.log(Object.keys(c1));

// Return all members (instance + prototype)
for (let key in c1) console.log(key);

console.log(c1.hasOwnProperty('move'));
console.log(c1.hasOwnProperty('draw'));

Prototypes - 8- Avoid Extending the Built-in Objects

不要修改不属于你的对象

Prototypes - 10- Exercise

function StopWatch() {
    this.startTime = 0; 
    this.endTime = 0; 
    this.running = 0; 
    this.duration = 0;

    Object.defineProperty(this, 'duration', {
        get: function() {
            return parseInt(this.endTime - this.startTime) / 1000;
        }
    });
}

StopWatch.prototype.start = function() {
    if (this.running)
        throw new Error('Already running')
        
    this.running = true;
    this.startTime = new Date();
}

StopWatch.prototype.stop = function() {
    if (!this.running)
        throw new Error('Not running')

    this.running = false;
    this.endTime = new Date();
};

StopWatch.prototype.reset = function() {
    this.running = false;
    this.startTime = 0;
    this.endTime = 0;
    this.duration = 0;
};

sw = new StopWatch();

Prototypes Inheritance - 1- Creating Your Own Prototypical Inheritance

function Shape() {
}

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

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

Circle.prototype = Object.create(Shape.prototype);

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

const s = new Shape();
const c = new Circle(1);

c.duplicate();
c.draw();

Prototypes Inheritance - 2- Resetting the Constructor

当重设原型对象之后,应该同时重设属性构造器

function Shape() {
}

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

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

// 当重设原型对象之后,应该同时重设属性构造器
// Circle.prototype.constructor = Circle;
// new Circle.prototype.constructor() <=> new Circle(); 即可以通过prototype的constructor方法创建对象
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;

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

const c = new Circle(1);

console.log(c.constructor);

Prototypes Inheritance - 3- Calling the Super Constructor

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

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

function Circle(radius, color) {
    // Child对象设置Parent对象的参数
    Shape.call(this, color);

    this.radius = radius;
}

Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;

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

const c = new Circle(1, 'red');

console.log(c);

Prototypes Inheritance - 4- Intermediate Function Inheritance

// 继承函数的写法
function extend(Child, Parent) {
    Child.prototype = Object.create(Parent.prototype);
    Child.prototype.constructor = Child;
}

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

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

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

    this.radius = radius;
}

extend(Circle, Shape);

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

const c = new Circle(1, 'red');

console.log(c);

Prototypes Inheritance - 5- Method Overriding

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

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

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

function Circle() {
}

extend(Circle, Shape);

// 方法的重写
Circle.prototype.duplicate = function() {
    Shape.prototype.duplicate.call(this);

    console.log('duplicate circle');
}

const c = new Circle();
c.duplicate();

Prototypes Inheritance - 6- Polymorphism

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

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

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();

Prototypes Inheritance - 7- When to Use Inheritance

在这里插入图片描述

  • 应避免创建层级式继承关系
  • 好的组合胜过继承

Prototypes Inheritance - 8- 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() {
}
mixin(Person.prototype, canEat, canWalk);

function Goldfish() {
}
mixin(Goldfish.prototype, canEat, canSwim);

const person = new Person();
const goldfish = new Goldfish();

console.log(person);
console.log(goldfish);

Prototypes Inheritance - 9- Exercise- Prototypical Inheritance

function HtmlElement() {
    this.click = function() {
        console.log('clicked');
    } 
}
HtmlElement.prototype.focus = function() {
    console.log('focused')
};

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

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

    this.removeItem = function(item) {
        this.items.filter(v => v!==item);
        // this.items.splice(this.items.indexOf(item), 1);
    }
}
// 若采用 HtlmSearchElemen.prototype = Object.create(HtmlElement.prototype); 只能继承baseHtmlElemenr,无法继承click方法
HtlmSearchElemen.prototype = new HtmlElement();
HtlmSearchElemen.prototype.constructor = HtlmSearchElemen;

const e = new HtmlElement();
const se = new HtlmSearchElemen();

Prototypes Inheritance - 11- Exercise- Polymorphism

// HtmlElement
function HtmlElement() {
    this.click = function() {
        console.log('clicked');
    } 
}
HtmlElement.prototype.focus = function() {
    console.log('focused')
};

// HtlmSearchElemen
function HtlmSearchElemen(items = []) {
    this.items = items;

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

    this.removeItem = function(item) {
        this.items.splice(this.items.indexOf(item), 1);
    }

    this.render = function() {
        s =  this.items.map(item => '<option>'+item+'</option>').join('\n'+'  ');
        s = `<select> \n  ${s}\n<select>`;
        return s;
        // another way
//         return `
// <select>${this.items.map(item => `
//   <option>${item}</option>`).join('')}
// </select>`;
//     }
}

HtlmSearchElemen.prototype = new HtmlElement();
HtlmSearchElemen.prototype.constructor = HtlmSearchElemen;

// HtmlImageElement
function HtmlImageElement(src = '') {
    this.src = src;

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

const elements = [
    new HtlmSearchElemen([1,2,3]),
    new HtmlImageElement('https://')
];

for (let ele of elements)
    console.log(ele.render());

ES6 Classes - 1- ES6 Classes

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

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

const c = new Circle(1);

ES6 Classes - 2- Hoisting

  • 函数声明会置顶(可以在定义之前被引用),函数表达式不会
// Class Declaration
class Circle {
}

// Class Expression
const Square = class{
};

ES6 Classes - 3- Static Methods

// 利用静态方法的方式创建不属于具体实例的工具函数
class Circle {
    constructor(radius) {
        this.radius = radius;
    }

    // Instance Method
    draw() {
    }

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

const circle = Circle.parse('{"radius": 1}');
console.log(circle);

ES6 Classes - 4- The This Keyword

class Circle {
    draw() {
        console.log(this);
    }
}

const c = new Circle();
// Method Call
c.draw();

// Function Call
const draw = c.draw;
draw();

ES6 Classes - 5- Private Members Using Symbols

// 利用Symbol来隐藏某些属性和方法(使其名称不可见,无法调用)
const _radius = Symbol();
const _draw = Symbol();

class Circle {
    constructor(radius) {
        this[_radius] = radius;
    }

    [_draw]() {
    }
}

const c = new Circle(1);

// 如果非要调用
const key = Object.getOwnPropertySymbols(c)[0];
console.log(c[key]);

ES6 Classes - 6- Private Members Using WeakMaps

const _radius = new WeakMap();
const _move = new WeakMap();

class Circle {
    constructor(radius) {
        _radius.set(this, radius);

        _move.set(this, () => {
            console.log('move', this);
        });
    }

    draw() {
        _move.get(this)();

        console.log('draw');
    }
}

const c = new Circle(1);
c.draw();

ES6 Classes - 7- 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);
console.log(c.radius);

ES6 Classes - 8- Inheritance

class Shape {
    constructor(color) {
        this.color = color;
    }

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

// 使用extends之后不用重设constructor
class Circle extends Shape {
    constructor(color, radius) {
        // 如果父类中由一个构造器,则子类的构造器必须先调用父类的构造器,以创建一个父类实例
        super(color);
        this.radius = radius;
    }

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

const c = new Circle('red', 1);
console.log(c);

ES6 Classes - 9- Method Overriding

class Shape {
     move() {
        console.log('move');
     }
}

// 使用extends之后不用重设constructor
class Circle extends Shape {
    move() {
        super.move();
        console.log('Circle move')
    }
}

const c = new Circle();
c.move();

ES6 Classes - 11- Exercise

const _items = new WeakMap();

class Stack {
    constructor() {
        _items.set(this, []);
    }

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

    peek() {
        if (_items.get(this).length === 0)
            throw new Error('Empty');

        return _items.get(this)[_items.get(this).length];
    }

    pop() {
        if (_items.get(this).length === 0)
            throw new Error('Empty');

        return _items.get(this).pop();
    }

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

}

const s = new Stack();

ES6 Tooling - 1- Modules

在这里插入图片描述

ES6 Tooling - 2- CommonJS Modules

  • 高度关联的东西应该放在一起
// Implementation Detail
const _radius = new WeakMap();

// Public Interface
class Circle {
    constructor(radius) {
        _radius.set(this, radius);
    }

    draw() {
        console.log('Circle with radius' + _radius.get(this));
    }
}

module.exports = Circle;
// require调用的模块和exports公开的对象是一样的
const Circle = require('./circle ');

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

ES6 Tooling - 3- ES6 Modules

// index
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Hello World</h1>
    <script type = "module" src="index.js"></script>
</body>
</html> 
// circle.js

// Implementation Detail
const _radius = new WeakMap();

// Public Interface
export class Circle {
    constructor(radius) {
        _radius.set(this, radius);
    }

    draw() {
        console.log('Circle with radius' + _radius.get(this));
    }
}
// index.js
import { Circle } from "./circle.js"; 

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

ES6 Tooling - 4- ES6 Tooling

在这里插入图片描述

ES6 Tooling - 5- Babel

  • node里的npm功能
npm init --yes
npm i babel -cli@6.26.0 babel -core@6.26.0 babel-preset-env@1.6.1 --save 

修改package.json
在这里插入图片描述

npm run babel

ES6 Tooling - 6- Webpack

sudo npm i -g webpack -cli@2.0.14
webpack-cli init

在这里插入图片描述

npm init --yes

在这里插入图片描述

npm run build
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值