本文最后更新于:2022-06-10T23:12:33+08:00
What is Object-oriented Programming
OOP是一种编程范例,或者编程风格,这是围绕对象而不是函数
面向对象编程中的四个核心概念
`Encapsulation`---封装 `Abstraction`---抽象 `Inheritance`---继承 `Polymorphism`---多态
区别与面向过程编程
改变了其中一个函数,然后其他几个函数可能就奔溃了,这就是我们说的意大利面条代码。
函数之间深层次的关联变成了各种问题的来源,OOP就应运而生。
OOP 就一组相关的变量和函数组成合成一个单元,我们称之为对象(object)。把里面的函数称为方法,里面的变量称之为属性。
最好的函数是那些没有参数的函数,参数个数越少,使用和维护就越简单。这就是封装!
多态意味着多种形态
使用封装重新组合的相关的变量和函数,这样可以减少复杂性,可以在程序的不同部分重用这些对象
或者在不同程序中,通过抽象,隐藏细节和复杂性,只显示必要性,这种技术降低了复杂性,也隔离了代码更改的影响。
继承让我们消除多余的代码
多态性可以避免写出复杂丑陋的选择性代码
原型与原型继承
原型Prototypes
和 原型继承Prototyical Inheritance
JavaScript 中的类并不同于 Java 或者 c#中的类,因为 Javascript 是动态语言,所以类的本质上是更像是为了配合原型和原型继承所采取的必要的技术。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| const circle = {};
function createCircle(radius) { return { radius, draw() { console.log("draw"); } }; } const circle2 = createCircle(1);
function Circle(radius) { this.radius = raius; this.draw = function() { console.log("draw"); }; } const circle3 = new Circle(2);
|
补充:
字面量是变量的字符串表示形式。它不是一种值,而是一种变量记法。
1 2 3 4
| const a = 1; const b = "hello world"; const c = [1, 2, 3]; const d = { foo: "bar" };
|
每个对象都有构造函数属性
这个属性引用了用来创建这个对象的构造函数
1 2 3 4
| new String(); new Boolean(); new Number(); new Object();
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| let number=10; function increase(number){ number++; } increase(number); console.log(number)
let object={value:10}; function increase(object){ object.value++; } increase(object); console.log(object)
````
不知道要访问的对象名称属性,是在运行时产生的,可以使用方括号的语法,或者属性名不符合命名规则时。
抽象意味着我们应该隐藏细节和复杂部分,只显示或者暴露必要的部分
```js this.defaultLocaltion={x:0,y:1} // ====> let defaultLocaltion={x:0,y:1} Object.defineProperty(this,'defaultLocaltion',{ get(){ return defaultLocaltion }, set(value){ defaultLocaltion=value } })
|
Javascript 中没有类,只有对象,那只有对象的时候如何引入继承?答案是原型。
原型可以理解为一个对象的父母,原型就是一般的对象。
1 2 3 4 5 6 7 8
| const person = { name: "hello" }; Object.defineProperty(person, "name", { writable: false, enumerable: true, configurable: false }); delete person.name; console.log(person);
|
获得对象原型的方法是调用 Object 对象的 getPrototypeOf 方法
1 2 3 4 5 6
| function Circle(radius) { this.radius = radius; } const circle = new Circle(1); Circle.prototype; circle.__proto__ === Circle.prototype;
|
Object.keys 只返回实例的成员
for-in 循环返回所有的成员,对象实例本身的和它的原型的
在 Javascript 中,有个函数可以从给定的原型创建对象,就是 Object.create(第一个参数是用作创建的原型)
Javascript 里每个对象都有一个构造函数属性,能返回用以创建这个对象的构造函数
避免创建层级式继承关系,因为这十分脆弱。如果要用继承特性,最好维持在一级。好的组合胜过继承。
Object.assign()可以用这个方法从一个对象拷贝所有成员到另外一个对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| const canEat = { eat: function() { console.log("eating"); } }; const canWalk = { walk: function() { console.log("eating"); } }; const canSwin = { swin: function() { console.log("swining"); } };
function mixins(target, ...sources) { Object.assign(target.prototype, ...sources); } function Dog() {} mixins(Dog, canEat, canWalk); console.log(new Dog()); function GoldFish() {} mixins(GoldFish, canEat, canSwin); console.log(new GoldFish());
|
ES6
函数声明 funciton sayHello(){}
结尾不需要加分号,函数声明是置顶的。
函数表达式const sayGoodbye=function(){}
结尾需要加分号,不会被置顶。
不同于函数,类声明和类表达式都不会被置顶
实例方法和静态方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Circle { constructor(radius) { this.radius = radius; } draw() {} static parse(str) { const { radius } = JSON.parse(str); return new Circle(radius); } } const circle = Circle.parse('{"radius":1}'); console.log("Go: circle", circle);
|
所以我们用静态方法的方式创建不属于具体实例的工具函数
1 2 3 4 5 6
| const c = new Circle(2);
c.draw(); const draw = c.draw;
draw();
|
ES6 私有
第一种是用在命名的时候加下划线
第二种是使用 Symbol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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]);
|
第三种是使用 WeakMap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const _radius = new WeakMap(); const _move = new WeakMap(); class Circle { constructor(radius) { _radius.set(this, radius); _move.set(this, () => { console.log("moving", this); }); } draw() { _move.get(this)(); console.log("drawing..."); } }
const c = new Circle(2); c.draw();
|
getter&&setter
方法重写
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Shape { move() { console.log("moving...."); } } class Circle extends Shape { move() { super.move(); console.log("circle move"); } }
const c = new Circle();
|
AMD,也就是异步模块定义,主要是在浏览器程序中使用。
CommonJS
class Circle{
}
module.exports.Circle=Circle
只需要引入一个模块时,可以简化代码module.exports=Circle
引入时,使用 require 函数。
所以时 CommonJS 定义了 require 函数和 module 函数,这是 CommonJS 当中的语法。
ES6
export && import
在模块化之前,要记住一个首要原则,高度关联的东西应该放在一起。就好比在厨房放置了杯子盘子勺子等餐具,不应该把衣服存放在厨房,这就是高度关联。这就是编程中说的 Cohesion(内聚)。
Webpack
- npm i -g webpack-cli
- webpack-cli init
- npm init —yes
完结