面向对象

面向对象(Oriented Object)

1、面向过程:

把解决问题的方法和步骤,一步一步写出来(JS代码);

2、面向对象:

Oriented Object (Analysis Design分析设计)

把解决问题的方法和步骤中,涉及到的属性和方法,封装成一个构造函数(对象),即对象的抽象

一、构造函数

构造函数.prototype 指向的是原型对象

实例对象.proto 指向的是原型对象

1、创建构造函数:

和普通函数的书写方式一样(命名以大驼峰方式)

创建方式,先创建一个空对象,然后创建这个对象的属性并赋值,添加到这个空对象中去,最后返回这个对象

function Students(name, age, gender) {
    // let this = {}
    this.name = name;
    this.age = age;
    this.gender = gender;
    // return this;    // 默认
}
let stu1 = new Students("xiaoguo", 18, "male");
let stu2 = new Students("xiaomi", 18, "famale");
console.log(stu1.name); // xiaoguo
console.log(stu2.name); // xiaomi
2、构造函数手动添加的返回值:

如果返回值是基本数据类型,默认返回值是不会改变的。

如果返回的是引用数据类型,默认返回值就会改变。

function Students(name, age, gender) {
    // let this = {}   // 在第一行先生成一个this空对象。
    this.name = name;
    this.age = age;
    this.gender = gender;
    // return this;    // 默认:JS会自动返回this对象
    // return 123;     // 无效:依然返回this对象
    // return [123];   // 有效:引用数据类型,则返回引用数据类型的对象,不返回this对象。
}
3、普通函数和构造函数本质区别:
1、调用方式不同:

普通函数是 函数名() ;

构造函数是 new 函数名();

类: new 类名();

2、返回值不同:

普通函数默认返回值是undefined,或者是return后面的

构造函数返回值是this这个对象

二、自动装箱,自动拆箱

内置对象(包装类)

A)自动装箱
let str = "abc";
// String length属性
console.log(str.length); // 3 (自动装箱)
1、基本数据类型:字符串

可以直接使用String的方法和属性

2、基本数据类型:数值

不可以直接使用toString的方法,原因:数值分整型和浮点型(小数)

// 123.toString() 	123后面的点,会被视为小数点,不会装箱为对象
// 解决方式如下:
(123).toString()
123.0.toString()
B)自动拆箱
let num = new String(456);
num.abc = 123;
// console.log(num.abc); // 123
// 自动转换为基本数据类型 String,然后字符串+1,字符串拼接为4561
console.log(num + 1); // 4561
// 自动转换为基本数据类型 String,然后字符串-1,隐式转换为数值456-1,最后输出455
console.log(num - 1); // 455

三、ES6类 class

类是对象的抽象, 对象是类的实例。

语法糖:ES6的书写方式

typeof 类 —function

注:类似封装一个构造函数;类就是函数

书写方式

class Students {
    // constructor 构造器
    constructor(name, age, gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    haha() {
        console.log('hahaha',this.name);
    }
};
let stu = new Students('z3', 18, 180);
console.log(stu.name); // z3
stu.haha(); // hahaha z3
// ES5可以使用普通函数调用方式,ES6会报错,提示调用前加 new
let stu5 = Students();

四、原型

1、判别属性是私有的还是公用的

注:同类别的实例对象可以使用公用的属性和方法

1)私有:
this.属性名 = 属性值;

this.方法名 = function () { };
2)公用:
.prototype.属性名 = 属性值;.prototype.方法名 = function () { };
实例.__proto__.属性名 = 属性值;
实例.__proto__.方法名 = function () { };
2、new 一个实例的工作流程

1、this的空对象

2、this的指向" proto “类.prototype”

3、执行代码(给this添加属性和方法)

4、return this(即返回对象给实例)

注:手动更改返回值

五、this

1、this 指向
1)对象中的this,

谁调用就指向谁

2)构造函数中的this

指向的是实例化对象

3)事件监听中的this

指向的是绑定事件的节点

4、普通函数中的this

指向的是window

注:严格模式下(“use strict”),指向的是undefined

let name = "cc";
var name = "dd";
function f70() {
    // "use strict"  严格模式
    console.log("A", this.name); // this 指向的是window
}
f70();
5、箭头函数中this的指向

取决于所处环境

注:箭头函数没有自己的 arguments,this

let str = x => console.log(this);
str(); // window
document.addEventListener("click", function () {
    let str = x => console.log(this);
    str(); // document
})
2、改变this指向
1、call 和 apply 是立即执行,

A)call传参第二个参数及之后的参数是以基本数据类型传入,

B)apply传参第二个参数是以数组的形式传参

2、bind不是立即执行的,

需要用一个变量来接收,使用时和函数一样需要调用他,

传参改变this指向的时候传参,也可以在调用的时候在传参,

传参可以传所有的参数也可以传部分的,他会自己识别参数

function F70 (name) {
    // let this = {};nh
    this.name = name;
    this.say = function (weight,height) {
        console.log(this.name,weight,height);
    }
}

let stu1 = new F70("asd");
// stu1.say(); // a

let stu2 = {
    name:"xiaoguo",
}
stu1.say.call(stu2,"80kg","188"); // xiaoguo 80kg 188 
stu1.say.apply(stu2,["70kg","188"]);; // xiaoguo 70kg 188 
let xiaoguoH = stu1.say.bind(stu2,"60kg","188");
xiaoguoH(); // xiaoguo 60kg 188 
stu1.say.bind(stu2,"60kg","188")();

六、原型

每个函数都有一个prototype属性叫原型

1、原型链

1、找自身的属性.方法,如果没有就做第二步,

2、在原型找属性.方法,如果没有就做第三步,

3、在原型的__proto__找属性

七、面向对象的三大特征

1)封装
A)ES5 构造函数添加属性和方法
function F70(name) {
    this.name = name;
    this.say = function () {
        console.log(this.name);
    }
}
B)ES6 属性和方法封装成一个对象
class F70{
    constructor(name){
        this.name = name;
    }
    say(){
        console.log(this.name);
    }
}
2)继承 (inherit)
A)ES5 版本 工作流程

通过构造函数的执行过程变相实现继承:

1)继承属性

a、先创建一个this空对象

b、通过构造函数的特点,把(传承者)这个构造函数赋值给自己的属性名,(产生一个新的方法)

c、执行这个方法,通过构造函数的执行过程 把他这个方法里面的所有属性添加到this这个对象中去,

d、删除这个方法,因为这个方法中的所有属性已经通过构造函数执行过程存储到this这个对象中去,变相实现了继承效果

e、最后实例化对象是就会返回这个this对象,所以(继承者)就能拿到(传承者)的属性

2)继承原型中的方法与属性

通过把(继承者)的原型的__proto__指向(传承者)的原型,(继承者)就能拿到(传承者)的原型,

就可以使用(传承者) prototype中的方法,并且不会覆盖自己的原型

Grand.prototype.hello = function () {
    console.log("hello");
}
function Grand() {
    this.name = "123";
}

Father.prototype.say = function () {
    console.log("abc");
}
function Father() {
    this.gender = true;
    this.age = 18;
}

function Son() {
    // 1)继承属性
    // a、先创建一个this空对象
    // b、通过构造函数的特点,把Grand这个构造函数赋值给自己的属性名,(产生一个新的方法)
    this.xiaoguo1 = Grand;
    // c、执行这个方法,通过构造函数的执行过程 把他这个方法里面的所有属性添加到this这个对象中去,
    this.xiaoguo1();
    // d、删除这个方法,因为这个方法中的所有属性已经通过构造函数执行过程存储到this这个对象中去,变相实现了继承效果
    delete this.xiaoguo;
    this.xiaoguo2 = Father;
    this.xiaoguo2();
    delete this.xiaoguo;
    this.gender = true;
    // e、最后实例化对象是就会返回这个this对象,所以s1就能拿到 Father 和 Grand的属性
}
// 2)继承原型中的方法和属性
// 通过把Son的原型的__proto__指向Father的原型,s1就能拿到Father的原型,
// 就可以使用Father prototype中的方法,并且不会覆盖自己的原型
Son.prototype.__proto__ = Father.prototype;
// 把Father的原型的__proto__指向Grand的原型,s1就能拿到Grand的原型,
// 就可以使用Grand prototype中的方法。
Father.prototype.__proto__ = Grand.prototype;
let s1 = new Son();
console.log(s1.age); // 18
s1.say();           // abc
s1.hello();         // hello
console.log(s1.name);// 123
2)ES6 版本

ES6继承 通过 关键字 extends 与 super实现

书写格式 :

A)在继承者的类名后面加 extends 和传承者(必须为类的名字),

B)然后在被继承者的constructor函数中添加super关键字并在小括号里面添加传承者的实参;

注:super必须写在所有this之前

class Father {
    constructor(money,name,age){
        this.name = name;
        this.age = age;
        this.money = money;
    }
    say(){
        console.log(this.name,this.age);
    };
}
// ES6继承 通过 关键字 extends 与 super实现
// 书写格式 :
// A)在继承者的类名后面加 extends 和传承者(必须为类的名字),
// B)然后在被继承者的constructor函数中添加super关键字并在小括号里面添加传承者的实参;
class Son extends Father {
    constructor(name,age,money){
        // super必须写在this之前
        super(money);
        this.name = name;
        this.age = age;
    }
    say(){
        console.log(this.name,this.age);
    }
}
let s1 = new Son("zx",12,"100w");
console.log(s1); 
3)多态

同一个构造函数或类,实力化出不同的对象(根据参数不同)

不同的实例对象,调用同一个方法,得到不同的结果

class Students{
    constructor(name,age,gender){
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    hello(place){
        console.log(this.name,place);
    }
}
let stu1 = new Students("zx",17,"male");
let stu2 = new Students("as",16,"famale");
let stu3 = new Students("vd",19,"male");

stu1.hello('DB'); // zx DB
stu2.hello('SC'); // as SC
stu3.hello('LS'); // vd LS

八、补充内容:扩展

1、对象中添加新的属性
let obj = {
    name: "zx",
}
obj.age = 123;
A)添加新属性
Object.defineProperty(obj, "gender", {
    // 设置属性值
    value: "male",
    // 设置新增属性可更改(true),默认false 不可更改
    writable: true,
    // 设置新增属性可遍历(true),默认false 不可遍历
    enumerable: true,
})
B)属性被赋值、更改、使用时

属性被赋值或更改时,触发set方法,

属性被使用时,触发get方法

Object.defineProperty(obj, "cc", {
    set(value) { // 设置的值
        if (value >= 40) {
            this.age = 18
        } else {
            this.age = 19
        }
    },
    get() { // 把结果反馈给cc
        return this.age;
    },
})
console.log(obj.age,obj); // 0
obj.cc = 40;
console.log(obj.age,obj); // 18
obj.cc = 20;
console.log(obj.age,obj); // 19
2、遍历对象中的属性值或属性名
A)遍历属性名
for (const index in obj) {
    console.log(obj[index]);
};
B)遍历属性值
for (const item of Object.keys(obj)) {
    console.log(item);
};
3、深拷贝,浅拷贝
A)浅拷贝:

公用一个地址,因此其中一个更改,另一个也会发生改变

let arr1 = [1,2,3];
let arr2 = arr
arr[2] = "a";
console.log(arr2); //[1,2,"a"]
console.log(arr);  //[1,2,"a"]
B)深拷贝:

不是同一个地址,因此其中一个改变,另一个不会发生改变

let arr1 = [1,2,3];
let arr2 = [];
// 方法1
// arr1.map(a=>arr2.push(a));
// 方法2
let arr2 = arr1.slice(0);
arr1[2] = "a";
console.log(arr1); // [1,2,"a"]
console.log(arr2); // [1,2,3]
4、扩展运算符(… )功能
1、批量修改和赋值;
let obj1 = {
    name: 1,
    age: 2,
}
let obj2 = {...obj1};
obj1.name = "a";
console.log("a",obj1);
console.log("b",obj2);
2、不定参数
function date(age,name,...time) {
    console.log(age,name,...time);
}
date(15,"zx","11点","12点") // 15 "zx" "11点" "12点"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值