欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-08 15:00:12
...

面向对象

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

对象创建模式

  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之前)
    JavaScript高级——面向对象、原型与原型链

原型链

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

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

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

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

  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