JavaScript高级——面向对象、原型与原型链

面向对象

  • 什么是面向对象编程
    • 面向对象不是一门技术,而是一种解决问题的思维方式
    • 面向对象的本质是对面向过程的一种封装
  • 理解什么是对象
    • 对象的本质是程序代码与现实世界沟通的一座桥梁。它有两种函数
      • 对象:是一种数据类型(存储数据的容器),以键值对的形式存储数据
      • 对象:对现实世界实物的一种抽象。

对象创建模式

  1. Object构造函数模式(内置构造函数)
    先创建空Object对象,再动态添加属性、方法
    适用场景:起始时不确定对象的内部数据
    问题:语句太多
	`	/* 
            一个人:name:"Tom",age=12
         */
        let p = new Object();
        p.name = 'Tom';
        p.age = 12;
        p.setName = function () {
            this.name = name;
        }
  1. 对象字面量
    使用{}创建对象,同时指定属性和方法
    适用场景:起始时对象的内部数据是确定的
    问题:如果创建多个对象有重复代码
		let p = {
            name: 'Tom',
            age: 12,
            setName: function (name) {
                this.name = name;
            }
        }
        let p2 = { //如果创建多个对象代码很重复
            name: 'Bob',
            age: 13,
            setName: function (name) {
                this.name = name;
            }
        }
  1. 工厂模式
    通过工厂函数动态创建对象并返回
    适用场景: 需要创建多个对象
    问题: 对象没有一个具体的类型(是人还是动物), 都是Object类型
	   function createPerson(name, age) { //返回一个对象的函数===>工厂函数
            let obj = {
                name: name,
                age: age,
                setName: function (name) {
                    this.name = name;
                }
            }
            return obj;
        }
         // 创建2个人
        let p1 = createPerson('Tom', 12);
        let p2 = createPerson('Bob', 13);

        // p1/p2是Object类型

        function createStudent(name, price) {
            let obj = {
                name: name,
                price: price
            }
            return obj;
        }
        let s = createStudent('张三', 12000)
        // s也是Object
  1. 自定义构造函数模式
    自定义构造函数, 通过new创建对象
    适用场景: 需要创建多个类型确定的对象
    问题: 每个对象都有相同的数据, 浪费内存
 		function Person(name, age) {
            this.name = name;
            this.age = age;
            this.setName = function (name) {
                this.name = name;
            }
        }
        let p1 = new Person('Tom', 22);
        p1.setName('Jack');
        console.log(p1.name, p1.age);
        console.log(p1 instanceof Person);

        function Student(name, price) {
            this.name = name;
            this.price = price;
        }
        let s = new Student('Bob', 13000);
        console.log(s instanceof Student);

        let p2 = new Person('JACK', 23);
        console.log(p1, p2);
  1. 构造函数+原型的组合模式

    自定义构造函数, 属性在函数中初始化, 方法添加到原型上
    适用场景: 需要创建多个类型确定的对象

		function Person(name, age) {
            this.name = name;
            this.age = age;
        }
        Person.prototype.setName = function () {
            this.name = name;
        }
        let p1 = new Person();
        let p2 = new Person();
        console.log(p1, p2);
new关键字工作原理

a.内置构造函数:[]:new Array() {}:new Object()
b.自定义构造函数: new Person()
(1)创建一个空对象:{}
(2)this指向这个对象
(3)执行对象的赋值代码
(4)自动返回这个对象 return this;

原型与原型链

原型对象(构造函数的工作原理)

  • 原型:任何构造函数在被创建的时候,系统都会自动帮我们创建一个与之对应的对象,称之为原型对象
    • 同时解决内存浪费与全局变量污染的问题
  • 谁可以访问原型对象中的成员(属性和方法)
    • 构造函数自身:构造函数名.prototype
    • 构造函数实例化的每一个对象:点语法直接访问
  • 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
    • 原型对象中有一个属性constructor, 它指向函数对象
  • 给原型对象添加属性(一般都是方法)
    • 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
<script>
  // 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
  console.log(Date.prototype, typeof Date.prototype)
  function Fun () {
  }
  console.log(Fun.prototype);  // 默认指向一个Object空对象(没有我们的属性)

  // 原型对象中有一个属性constructor, 它指向函数对象
  console.log(Date.prototype.constructor===Date);
  console.log(Fun.prototype.constructor===Fun);

  //给原型对象添加属性(一般是方法) ===>实例对象可以访问
  Fun.prototype.test = function () {
    console.log('test()');
  }
  let fun = new Fun();
  fun.test();
</script>

prototype__proto__constructor

  1. 每个函数function都有一个prototype,即显式原型(属性)
  2. 每个实例对象都有一个__proto__,可称为隐式原型(属性)
  3. 对象的隐式原型的值为其对应构造函数的显式原型的值
  4. 原型对象中有一个属性constructor, 它指向函数对象
  5. 总结:
  • 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象
  • 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
  • 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
    在这里插入图片描述

原型链

  • 原型链 :每一个对象都有__proto__属性指向自己的原型,而原型又是一个对象,也有自己的__proto__属性指向原型的原型,以此类推形成一种链式结构,称之为原型链(别称隐式原型链)。

  • 对象访问原型链中成员的规则:就近原则
    对象访问成员的时候,优先访问自己的。自己没有就访问原型的,如果原型也没有,就访问原型的原型,以此类推直到原型链终点Null . 如果还找不到,如果是属性则获取undefined. 如果是方法则报错, 提示 ‘xxx’ is not a function.

在这里插入图片描述

面向对象的思维方式的三大特征

  1. 封装:将代码放入对象的方法中
  2. 继承:一个对象拥有另一个对象的所有成员(属性+方法)
    (1)自己实现继承的3种方式
    2.1 混入式继承:遍历父对象成员 添加给子对象
    场景:用于单对象继承
    2.2 替换原型:将父对象 作为子对象的构造函数的原型
    场景:用于多对象继承
    2.3 混合式:混入式 + 替换原型
    场景:遍历父对象,添加给子对象的原型
    (2)js是通过原型链来实现继承的
  3. 多态:一个对象在不同情况下的多种状态
    javascript语言很少用到多态
instanceof运算符 : 检测一个构造函数prototype 在不在对象的原型链中。
        语法:  实例对象  instanceof 构造函数
        规则: 检测 右边构造函数的prototype 在不在左边对象的原型链中
        true: 在  false:不在

        let arr = [10,20,30];
        /* 
        arr实例对象原型链  arr.__proto__  ->  Array.prototype -> Object.prototype - > null
        */
        console.log( arr instanceof Array);//true
        console.log( arr instanceof Object);//true

        /* 
        根据instanceof运算符规则: 左边object是一个对象,  右边object是一个函数
        object对象原型链 object.__proto__ -> Function.prototype ->Object.prototype ->null
        
        */
       console.log( Object.__proto__.constructor );//Function
       console.log( Object.__proto__ === Function.prototype );//true
    
        console.log( Object instanceof Object);//true
        console.log( Object instanceof Function);//true


        /* 
        根据instanceof运算符规则: 左边Functiont是一个对象,  右边Function是一个函数
        function对象原型链 Function.__proto__ -> Fuction.prototype -> Object.prototype -> null
        */
        console.log( Function.__proto__.constructor );//Function
        console.log( Function.__proto__ === Function.prototype );//true

        console.log( Function instanceof Function);//true
        console.log( Function instanceof Object);//true

猜你喜欢

转载自blog.csdn.net/weixin_44757417/article/details/107844703