JS面向对象

1.面向对象的基本概念

面向对象

1.1 面向对象思想

  • 面向对象(Object Oriented,OO)是软件开发方法
  • 面向对象是一种对现实世界抽象的理解,是计算机编程技术发展到一定阶段后的产物
  • Object Oriented Programming-OOP ——面向对象编程

1.2 面向对象和面向过程区别

内容强调关注
面向过程强调的是功能行为关注的是解决问题需要哪些步骤
面向对象将功能封装进对象,强调具备了功能的对象关注的是解决问题需要哪些对象
  • 面向对象是基于面向过程而言

  • 面向对象和面向过程都是一种思想

2. 类与对象的关系

2.1 使用默认类创建对象

2.1.1 通过 new Object() 创建对象

  • 1.JavaScript中提供了一个默认的类Object, 我们可以通过这个类来创建对象

  • 2.由于我们是使用系统默认的类创建的对象, 所以系统不知道我们想要什么属性和行为, 所以我们必须手动的添加我们想要的属性和行为

  • 3.如何给一个对象添加属性

    对象名称.属性名称 = 值;

  • 4.如何给一个对象添加行为

    对象名称.行为名称 = 函数;

		// 创建对象的第一种方式 		
 		let obj = new Object(); 
        obj.name = "sss";
        obj.age = 33;
        obj.say = function () {
            console.log("hello world");
        }
        console.log(obj.name);
        console.log(obj.age);
        obj.say();

2.1.2 使用字面量创建对象

		let obj = {}; // 相当于 let obj = new Object();
        obj.name = "lnj";
        obj.age = 33;
        obj.say = function () {
            console.log("hello world");
        }
        console.log(obj.name);
        console.log(obj.age);
        obj.say();
       
        // 注意点: 属性名称和取值之间用冒号隔开, 属性和属性之间用逗号隔开
        let obj = {
            name: "sss",
            age: 33,
            say: function () {
                console.log("hello world");
            }
        };
        console.log(obj.name);
        console.log(obj.age);
        obj.say();

2.1.3 工厂函数创建对象

上面的创建方式, 每多创建一个人都需要将代码再写一遍, 冗余代码太多, 所以可以创建创建对象的代码封装到一个函数中

专门用于创建对象的函数我们称之为工厂函数

		function createPerson(myName, myAge) {
            let obj = new Object();
            obj.name = myName;
            obj.age = myAge;
            obj.say = function () {
                console.log("hello world");
            }
            return obj;
        }
        let obj1 = createPerson("lnj", 34);
        let obj2 = createPerson("zs", 44);
        console.log(obj1);
        console.log(obj2);

2.1.4 构造函数创建对象

因为工厂函数创建对象并不专业,所以又引申出了构造函数

1.什么是构造函数
  • 构造函数和工厂函数一样, 都是专门用于创建对象的
  • 构造函数本质上工厂函数的简写
2.构造函数和工厂函数的区别
  • 2.1 构造函数的函数名称首字母必须大写
  • 2.2 构造函数只能够通过new来调用
		function Person(myName, myAge) {
            // let obj = new Object();  // 系统自动添加的
            // let this = obj; // 系统自动添加的
            this.name = myName;
            this.age = myAge;
            this.say = function () {
                console.log("hello world");
            }
            // return this; // 系统自动添加的
        }
        let obj1 = new Person("ls", 34);
        let obj2 = new Person("zs", 44);
        console.log(obj1); // Person
        console.log(obj2); // Person
        /*
		1.当我们new Person("ls", 34);系统做了什么事情
		1.1会在构造函数中自动创建一个对象
		1.2会自动将刚才创建的对象赋值给this
		1.3会在构造函数的最后自动添加return this;	
		*/
3.构造函数的方法中的this谁调用就是谁

函数和方法的区别

		function Person(myName, myAge) {
            this.name = myName;
            this.age = myAge;
            this.say = function () {
                // 方法中的this谁调用就是谁
                console.log(this, this.name, this.age);
            }
        }
        let obj1 = new Person("sss", 34);
        obj1.say();

        let obj2 = new Person("zs", 44);
        obj2.say();

在这里插入图片描述

4.构造函数的性能问题

创建一个对象就会在内存开辟一块存储空间

在这里插入图片描述

由于两个对象中的say方法的实现都是一样的, 但是保存到了不同的存储空间中,所以有性能问题

5.构造函数的优化
1.prototype
  • JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象
  • 这个对象的所有属性和方法,都会被构造函数的所拥有
  • 也就意味着,可以把所有对象实例需要共享的属性和方法直接定义在 prototype 对象上
		function Person(myName, myAge) {
            this.name = myName;
            this.age = myAge;
        }
        Person.prototype = {
            say: function () {
                console.log("hello world");
            }
        }
        let obj1 = new Person("sss", 34);
        obj1.say();
        let obj2 = new Person("zs", 44);
        obj2.say();
        console.log(obj1.say === obj2.say); // true

prototype的相关注意点

3. 面向对象三大特性

封装性

1.什么是封装?

封装性就是隐藏实现细节,仅对外公开接口

2.为什么要封装?

  • 不封装的缺点:当一个类把自己的成员变量暴露给外部的时候,那么该类就失去对属性的管理权,别人可以任意的修改你的属性
  • 封装就是将数据隐藏起来,只能用此类的方法才可以读取或者设置数据,不可被外部任意修改. 封装是面向对象设计本质(将变化隔离)。这样降低了数据被误用的可能 (提高安全性和灵活性)
		function Person() {
            this.name = "lnj";
            // this.age = 34;
            let age = 34;
            this.setAge = function (myAge) {
                if (myAge >= 0) {
                    age = myAge;
                }
            }
            this.getAge = function () {
                return age;
            }
            this.say = function () {
                console.log("hello world");
            }
            /*
            // 由于构造函数也是一个函数, 所以也会开启一个新的作用域
            // 所以在构造函数中通过var/let定义的变量也是局部变量
            // 所以在构造函数中定义的函数也是局部函数
            var num = 123;
            let value = 456;
            function test() {
                console.log("test");
            }
            */
        }
        let obj = new Person();
        // 结论: 默认情况下对象的属性和方法都是公开的, 只要拿到对象就可以操作对象的属性和方法
        // console.log(obj.name);
        // obj.age = -3;
        // console.log(obj.age);
        // obj.say();

        // console.log(age); // 无法直接获取以及修改
        obj.setAge(-3); // 提供给修改的接口以及控制输入的内容
        console.log(obj.getAge()); // 提供获取的接口

3.私有属性变量和函数

默认情况下对象中的属性和方法都是公有的, 只要拿到对象就能操作对象的属性和方法
外界不能直接访问的变量和函数就是私有变量和私有函数

3.1 私有属性注意点

在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找, 如果当前对象没有就会给当前对象新增一个不存在的属性

由于私有属性的本质就是一个局部变量, 并不是真正的属性, 所以如果通过 对象.xxx的方式是找不到私有属性的, 所以会给当前对象新增一个不存在的属性

		function Person() {
            this.name = "lnj";
            let age = 34;
            this.setAge = function (myAge) {
                if (myAge >= 0) {
                    age = myAge;
                }
            }
            this.getAge = function () {
                return age;
            }
            this.say = function () {
                console.log("hello world");
            }
        }
        let obj = new Person();
        // 1.操作的是私有属性(局部变量)
        obj.setAge(-3);
        console.log(obj.getAge());
        // 2.操作的是公有属性
        obj.age = -3;
        console.log(obj.age);

4.属性和方法分类

1.实例属性/实例方法

在企业开发中通过实例对象访问的属性, 我们就称之为实例属性
在企业开发中通过实例对象调用的方法, 我们就称之为实例方法

		function Person() {
            this.name = "lnj";
            this.say = function () {
                console.log("hello world");
            }
        }
        // 通过构造函数创建的对象, 我们称之为"实例对象"
        let obj = new Person();
        console.log(obj.name);
        obj.say();

        obj.age = 34;
        console.log(obj.age);
        obj.eat = function () {
            console.log("eat");
        }
        obj.eat();
2.静态属性/静态方法

在企业开发中通过构造函数访问的属性, 我们就称之为静态属性
在企业开发中通过构造函数调用的方法, 我们就称之为静态方法

		function Person() {
            this.name = "lnj";
            this.say = function () {
                console.log("hello world");
            }
        }
        // 构造函数也是一个"对象", 所以我们也可以给构造函数动态添加属性和方法
        Person.num = 666;
        Person.run = function () {
            console.log("run");
        }
        console.log(Person.num);
        Person.run();

继承性

  • js中继承目的: 把子类型中共同的属性和方法提取到父类型中
  • 较少代码的冗余度, 提升代码的复用性

实现继承的方法

其他方法

4. 终极方案
  • 1在子类的构造函数中通过call借助父类的构造函数
  • 2将子类的原型对象修改为父类的实例对象
    在这里插入图片描述

Student.prototype = new Person();
Student.prototype.constructor = Student;

		function Person(myName, myAge) {
            // let per = new Object();
            // let this = per;
            // this = stu;
            this.name = myName; // stu.name = myName;
            this.age = myAge; // stu.age = myAge;
            // this.say = function () { // stu.say = function () {}
            //     console.log(this.name, this.age);
            // }
            // return this;
        }
        Person.prototype.say = function () {
            console.log(this.name, this.age);
        }
        function Student(myName, myAge, myScore) {
            Person.call(this, myName, myAge);
            this.score = myScore;
            this.study = function () {
                console.log("day day up");
            }
        }
		Student.prototype = new Person();
		Student.prototype.constructor = Student;
		Student.prototype.run = function(){
            console.log("run");
        }

        let per = new Person();
        per.run(); // 报错

多态

1.什么是多态?

    多态是指事物的多种状态
    例如:
    按下 F1 键这个动作,
    如果当前在 webstorm 界面下弹出的就是 webstorm 的帮助文档;
    如果当前在 Word 下弹出的就是 Word 帮助;
    同一个事件发生在不同的对象上会产生不同的结果。

2.多态在编程语言中的体现

    父类型变量保存子类型对象, 父类型变量当前保存的对象不同, 产生的结果也不同

4.ES6类和对象

1.在ES6之前如果定义一个类?

通过构造函数来定义一个类

2.从ES6开始系统提供了一个名称叫做class的关键字, 这个关键字就是专门用于定义类的

class Person{
            // 当我们通过new创建对象的时候, 系统会自动调用constructor
            // constructor我们称之为构造函数
            constructor(myName, myAge){
                this.name = myName;
                this.age = myAge;
            }
            // 实例属性
            // name = "lnj";
            // age = 34;
            // 实例方法
            say(){
                console.log(this.name, this.age);
            }
            // 静态属性
            static num = 666;
            // 静态方法
            static run() {
                console.log("run");
            }
        }
        // let p = new Person();
        let p = new Person("zs", 18);
        p.say();
        console.log(Person.num);
        Person.run();

1. 以下定义"实例属性"的方式并不是ES6正式版标准中的写法, 大部分的浏览器不支持

在ES6标准中添加实例属性都需要在constructor中添加

// 实例属性
// name = "lnj";
// age = 34;
constructor(){
    this.name = "lnj";
    this.age = 34;
}

2. 以下定义"静态属性"的方式并不是ES6正式版标准中的写法, 大部分的浏览器不支持

在ES标准中static只支持定义静态方法不支持定义静态变量

class Person {
	// 静态属性
	// static num = 666;

	// 静态方法
	static run() {
   	console.log("run");
	}
}
// 静态属性
Person.num = 666;
let p = new Person();
console.log(p);

3.constructor 内写内容相当于之前在构造函数中编写,而在constructor以外编写的相当于在prototype原型上

		function Person(myName, myAge) {
            // 实例属性
            this.name = myName;
            this.age = myAge;
            // 实例方法
            this.hi = function () {
                console.log("hi");
            }
        }
        Person.prototype.say = function () {
            console.log(this.name, this.age);
        }
        let p = new Person("lnj", 34);
        console.log(p);

在这里插入图片描述

 		class Person{
            constructor(myName, myAge){
                this.name = myName;
                this.age = myAge;
                this.hi = function () {
                    console.log("hi");
                }
            }
            say(){
                console.log("hi");
            }
        }
        let p = new Person("lnj", 34);
        console.log(p);

4.在prototype上添加属性和方法

注意点:

如果通过class定义类, 那么不能自定义这个类的原型对象

如果想将属性和方法保存到原型中, 只能动态给原型对象添加属性和方法

  • ES6之前,构造函数
		function Person(myName, myAge) {
            // 实例属性
            this.name = myName;
            this.age = myAge;
            // 实例方法
            this.hi = function () {
                console.log("hi");
            }
        }
        // 原型上的方法
        // Person.prototype.type = "人";
        // Person.prototype.say = function () {
        //     console.log(this.name, this.age);
        // };
        Person.prototype = {
            constructor: Person,
            type: "人",
            say: function () {
                console.log(this.name, this.age);
            }
        };
  • ES6
		class Person{
            constructor(myName, myAge){
                this.name = myName;
                this.age = myAge;
                this.hi = function () {
                    console.log("hi");
                }
            }
            run(){
                console.log("run");
            }
        }
        // 方法一:
        // Person.prototype.type = "人";
        // Person.prototype.say = function () {
        //     console.log(this.name, this.age);
        // };
		// 方法二:
        let obj = {
            constructor: Person,
            type: "人",
            say: function () {
                console.log(this.name, this.age);
            }
        };
        Person.prototype = obj;

        let p = new Person("lnj", 34);
        console.log(p);

在这里插入图片描述

2.ES6继承

1.ES6之前的继承

  • 1.在子类中通过call/apply方法借助父类的构造函数
  • 2.将子类的原型对象设置为父类的实例对象

2.在ES6中如何继承

  • 1在子类后面添加extends并指定父类的名称
  • 2在子类的constructor构造函数中通过super方法借助父类的构造函数
		class Person{
            constructor(myName, myAge){
                // this = stu;
                this.name = myName; // stu.name = myName;
                this.age = myAge; // stu.age = myAge;
            }
            say(){
                console.log(this.name, this.age);
            }
        }
        /*
        1.在ES6中如何继承
        1.1在子类后面添加extends并指定父类的名称
        1.2在子类的constructor构造函数中通过super方法借助父类的构造函数
        */
        // 以下代码的含义: 告诉浏览器将来Student这个类需要继承于Person这个类
        class Student extends Person{
            constructor(myName, myAge, myScore){
                // 1.在子类中通过call/apply方法借助父类的构造函数
                // Person.call(this, myName, myAge);
                super(myName, myAge);
                this.score = myScore;
            }
            study(){
                console.log("day day up");
            }
        }
        let stu = new Student("zs", 18, 98);
        stu.say();

参考来源

学习笔记❥(^_-),版权归Jonathan

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值