面向对象 11.19
标签(空格分隔): 面向对象
面向对象(oop)是一种编程思想,对象都是通过实例化类得到的。对象是客观事物的抽象,类是对象的抽象;
KX
封装:不用关系某个类的内部实现,只需要去使用它;
继承:通常是和类之间的行为,子类继承与父类
多态:继承之后的子类,可以有自己独特的属性和行为;
- 对象 = new 类();
- 对象是通过实例化类得到的,实例化过程就是 new xxx 的过程;
- 例如: const obj1 = {}; const obj2 = new Object() ;Object() 就是个类
构造函数
// 当 new 去调用一个函数:这个时候函数中的 this 就是创建出来的对象,而且函数返回值 直接就是 this(隐式返回)
// new 后面调用的函数:就叫做构造函数
eg: function CreatePerson(name) {
this.name = name;
}
var p1 = new CreatePerson('小明');
var p2 = new CreatePerson('小强');
console.log(p1 == p2 ); // false
用原型的方法改写
CreatePerson.protopyte.showName = function() {
console.log(this.name);
}
var p1 = new CreatePerson('小明');
var p2 = new CreatePerson('小强');
console.log(p1 == p2 ); // true
原型
// 原型:去改写对象下面公用的方法或者属性,让公用的方法或者属性在内存中存在一份,(提高性能)
//原型的写法:prototype: 要写在构造函数的下面
eg: var arr = [1,2,3,4,5];
Array.protype.sum = function() {
var result = 0;
for(var i=0 ;i<this.length; i++){ // this 指向的是 arr
result += arr[i];
}
}
arr.sun();
面向对象的写法总结
//属性:属性是变化的 要放在构造函数中;
// 能公用的方法放到原型中
function 构造函数(){
this(对象).属性
}
构造函数.原型(prototype).方法 = function() {
---- 能公用的方法放到原型中
}
//面向对象的使用
var 对象1 = new 构造函数();
对象1.方法();
定义一个类;
- 定义一个类使用 class 加类的名字 + {};
- 类的名字首字母 大写;
-[3]: class Ball{}; // Ball 就是一个类;
-[4]: const ball = new Ball(); /// [3]跟 【4】 表达的是一个意思;
class Ball{} // 只是空定义一个类,这个类里面什么都没有; 这样实例化一个类,只会得到一个空对象;
constructor(){} 方法
constructor方法是类的默认方法,通过new命令生成对象实例化时,自动调用该方法。一个类必须有constructor方法如果没有显式定义,一个空的constructor方法会被默认添加;
- constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
class Person{
constructor(){ //代表Persion 类的构造函数
// 在这里面可以定义这个类的属性(通常只是属性);
//console.log(123);
//consolelog(this); // 这里面的this 代表实例化出来的对象
// 如果这里不写return ,默认返回的是实例化出来的这个对象,如果写了return,如果返回的是一个基本数据类型,那么会忽略,依然返回当前实例化的这个对象,如果return后面是一个对象,那么就会返回这个对象,而不是实例化的对象了。
// return 1;
// return [1,2,3,4];
}
}
const p1 = new Persion(); // 实例化对象
console.log(p1);
实例化类
定义一个人类,具有名字和年龄的属性 ,同时具有一个介绍自己的方法
constructor 翻译 构造函数
class Person {
constructor(name, age){
this.name = name;
this.age = age;
} // 后面不能添加逗号
say(){ // 自定义的方法
// 凡是这个类所有拥有的方法,内部的this默认都指向实例化出来的对象
let {name, age} = this;
console.log(My name is ${name}, my age is ${age}.
);
}
}
const xiaoyuren = new Person(‘小鱼人’, 1000);
const wuguiren = new Person(‘忍者龟’, 19999);
// console.log(xiaoyuren);
// console.log(wuguiren);
xiaoyuren.say();
wuguiren.say();
定义类的表达式;
const person = class {}; // ==> class Person{} ;这2个是一个意思;
const Person = class Per {} // Person 才是这个类的名字, Per 不是
class 的静态方法;
使用 static 来定义静态方法,静态方法是类的方法,而不是对象的,静态方法内部this指的是类,而不是对象。
class Person {
constructor(name){
this.name = name;
}
say(){
console.log(`I'm ${this.name}`);
}
static sayClass(){
console.log(`我是一个人类!`);
this.say();
}
static say(){
console.log(`我是一个类`);
}
}
const p1 = new Person('老王');
p1.say();
// p1.sayClass(); 报错
Person.sayClass();
class 的继承;
> 子类 extends 父类 {} 就可以继承;
class Person {
constructor(name, age){
this.name = name;
this.age = age;
}
walk(){
setInterval(function(){
console.log(`${this.name}走了`);
},1000);
static fn(){
alert(123);
}
}
// ---------------------------------
// class Laowang extends Person {};
//
// const laowang = new Laowang('老王1', '20');
//
// console.log(laowang);
// 上面这么写,相当于复制了一份 Person 类
// ---------------------------------
class Laowang extends Person {
constructor(name, age, sex){
// console.log(this); // 没调用 super 之前不能使用 this
super(name, age); // 这个方法必super须调用, 否则就会报错
// 只有调用了super 方法之后,才能使用 this,否则子类没有自己的this
this.sex = sex;
}
say(){
// super(); super 不能在自定义的方法中去当成函数调用。
// this.walk();
// super.walk();
// super 在自定义的方法中,不能当作函数调用,但是可以代表继承的 那个父类,然后调用父类具有的方法。
console.log(`我是某个隔壁的${this.name},我的年龄是${this.age},我的性别是${this.sex}`);
}
walk(){
setInterval(function() {
console.log(`${this.name}走了`);
}, 200);
}
}
const lw = new Laowang('老王', '28', '老爷们');
// lw.say();
// lw.walk();
// console.log(lw);
// 继承的时候 子类 会集成 父类的 静态方法
// Laowang.fn();
// -------------------------------------------
class SuperArray extends Array {
constructor(...rest){
super(...rest);
}
fn(){
console.log(this);
}
}
const arr = new SuperArray(1, 2, 3);
console.log(arr);
#### 确定随机范围
function rp(arr, int){
var min = Math.min(...arr); // arr 是个数组 , (...arr) 相当于把 把ARR里面的每一个数单独拆分出来
var max = Math.max(...arr);
var ret = Math.random() * (max - min) + min; // 确定随机数的范围
return int ? Math.round(ret) : ret;
}
#### 产生随机颜色
function createColor(){
return `rgb(${rp([55, 255], true)}, ${rp([55, 255], true)}, ${rp([55, 255], true)})`;
}
选项卡案例(11.19) 课件;
# 11.21
* 在JS这个大工厂中,有一个原型产品即:对象的原型 --- Object.prototype
* 通过对象的原型,首先创造除了另外一个加强版的原型产品 --- * * Function.prototype (空函数)
* 通过 Function.prototype 这个原型产品制造出了两个非常强大机器函数:Object 和 Function
* Object 函数 用来批量生产对象
* Function 函数 用来批量生产 其它不同功能的函数
*
* Object 和 Function 都称之为构造函数,每个构造函数都有一个 prototype 属性,
* 可以生产出基于这个原型的产品,它们通过 new 构造函数 的方式去实例化自己的产品,
* 并且为每个产品打上一个标签__proto__,用来表明这个产品的原型是谁,同时每个
* prototype身上都有一个 constructor 属性,用来指明这个原型的构造函数是谁。
* 原型本身也是一个对象,构造函数不仅仅能生产普通的函数,也能生产构造函数。
#### 构造函数
- 构造函数: 比如 new Object() 相当于 得到一个 {},那么 这个 Object 实际上就是一个构造函数,通过这个例子,可以发现构造函数的特征:
【1】 使用 new 去调用的函数
【2】 使用 new 去调用的函数
通过 new 去调用一个构造函数,称之为对象的实例化。
除了JS自带的构造函数,自己也可以去定义自己的构造函数,就像使用 class 去定义一个 类 一样。
#### prototype 属性
- 每个函数都有一个 prototype 属性,但是只有当这个函数当作构造函数使用的时候这个属性才会生效。
- 构造函数.prototype 本身是一个对象,也是这个构造函数实例化出来对象的原型,所以所有通过这个 构造函数实例化出来的对象都会记住并且可以访问它们自己的原型。
- 原型中有一个特殊的属性 constructor,它在函数创建的时候有JS引擎自动添加,用来表明这个原型的构造函数是谁。但是这个属性可读可写,所以它并不可靠。同时 这个属性 是一个 不可以被枚举的。
- 枚举:凡是可以被for...in循环所循环到的属性,都是可以枚举的 enumerabled。反之都是不可以被枚举的,比如 数组的 length 属性, 对象的 __proto__ 属性。
```python
function Car(name, engin){
this.name = name;
this.engin = engin;
this.didi = function (){
console.log('嘀嘀');
};
}
const benchi = new Car('奔驰', 'v8');
const falali = new Car('法拉利', 'v12');
benchi.didi();
falali.didi();
每次实例化这个构造函数的时候都会得到一个新的方法
console.log(benchi.didi === falali.didi); // false
// ---------------------------------------------
function Car(name, engin){
this.name = name;
this.engin = engin;
}
const benchi = new Car('奔驰', 'v8');
const falali = new Car('法拉利', 'v12');
console.log(benchi.__proto__ === falali.__proto__);
console.log(falali.__proto__ === Car.prototype);
Car.prototype.didi = function (){
console.log('嘀嘀');
};
benchi.didi();
falali.didi();
console.log(benchi.didi === falali.didi);
<div class="se-preview-section-delimiter"></div>
原型链
- 每个被构造函数实例化出来的对象,都会记住它自己的原型(proto),而每个原型也是一个对象,
- 所以原型对象也会记住它自己的原型,最终它们都会找到一个顶级原型对象 Object.prototype
- 可以发现,它们之间彼此互相关联,这个关联就称之为原型链。
当访问一个对象的某个属性的时候,先在自身进行查找,如果自身没有,那么就会顺着原型链去查找,直到找到 Object.prototype
Object.prototype.a = 10; function Fn(){ // this.a = 1; } Fn.prototype.a = 5; const f = new Fn(); console.log(f.a); // ----------------------------------- function Person(name){ this.name = name; } Person.prototype.say = function (){ console.log(this.name); }; //----------------------- Person.prototype = { constructor: Person, // 记住需要手动修正 say(){ console.log(this.name); } }; const p1 = new Person('老王'); // p1.say(); // console.log(p1.constructor); console.log(p1);
in和hasOwnProperty
对象.hasOwnProperty(属性),用来判断这个属性是不是这个对象自身的。
const obj = {a: 1};
Object.prototype.b = 2;
//xxx in obj 看 xxx 属性在不在 obj 当中,在就返回 true,否则就返回 false
// console.log('a' in obj);
// console.log('b' in obj); // true
// in 不能判断是否是自身的属性
console.log(obj.hasOwnProperty('a')); // true
console.log(obj.hasOwnProperty('b')); // false
<div class="se-preview-section-delimiter"></div>
instanceof
- instanceof 运算符表示 a(对象) 是否是 b(构造函数) 的实例。
- [] instanceof Array 为 true, [](空数组)是一个数组(Array 类的实例)
- Array instanceof Function 为 true, Array(类构造器)是一个函数(Function 类的实例)
- [] instanceof Function 是 false, [](空数组)不是一个函数(Function 类的实例)
- 深入 instanceof : instanceof关键字的作用是判断实例对象是否是原型链上出现过的构造函数的实例对象
深入理解new (模拟new)
function Person(name){
this.name = name;
// return [1, 2, 3];
}
Person.prototype.say = function (){
console.log(this.name);
};
// const p1 = new Person('皮皮虾');
function whatIsNew(){
// const obj = {}; // 从 Object.prototype 身上克隆一个空对象
const obj = Object.create(null); // 创造一个空对象
const args = [...arguments]; // 把arguments转成数组
const Constructor = args.shift(); // 拿到第一个参数,构造函数
obj.__proto__ = Constructor.prototype;
const ret = Constructor.apply(obj, args);
return typeof ret === 'object' ? ret : obj;
}
const p2 = whatIsNew(Person, '皮皮虾');
console.log(p2);
总结
1 所有的对象都是数据,但是数据不一定都是对象
2 要得到一个对象,js中不是实例化类,而是找到一个对象并且克隆它
3 对象会记住自己的原型
4 如果一个对象无法响应某个请求,他会把这个请求委托给自己的原型继承;