目录
面向对象
对象
构造函数
this关键字
原型
- 面向对象
 
面向过程: 在开发过程中,关注过程的开发方式. 在开发时关注每一个细节,步骤和顺序.
面向对象: 在开发过程中,只需要找一个对象来完成事情的开发思想
对象: 在生活中,万物皆对象
封装: 将完成步骤封装在对象内部
属性: 对象的特征
核心: ①制造一个对象, 批量生产对象; ②每个对象都有自己的属性(特征)和方法(函数,行为); ③每个对象都类似,但不相同(构造函数)
e.g:
(1)想吃饭
面向过程:
-> 所有事情自己亲力亲为
-> 考虑顺序: 烧水, 洗菜, 切菜, 炒菜...
-> 考虑细节: 切菜时,菜切的花样
面向对象:
-> 只需要到饭店去点菜 (不关注菜如何做, 找一个做饭的对象)
(2)开发选项卡
面向过程:
-> 考虑获取哪些元素? tab标签, 每一个tab标签对应的内容区域
-> 考虑给哪些元素绑定点击事件? tab标签绑定点击事件
-> 考虑点击的功能? 进行内容的切换
面向对象:
-> 找到一个能完成选项卡功能的对象, 让这个对象来完成
-> 注意: 这个对象是否存在? 存在则直接使用, 不存在则制造对象(创建对象)
制造对象:
-> 我们需要一个制造对象的机器(抽象的概念)
-> 机器的作用是: 生产一个对象(具体的概念)
-> 生产出来的对象要能够完成选项卡的功能
-> 因此, 我们只需要准备这个机器
-> 开发过程中, 只需要造机器, 由机器生产出来的一个对象来完成选项卡功能, 当开发另一个选项卡时, 不需再次制造机器, 只需要该机器再生产一个对象来完成另一个选项卡功能即可
- 对象
 
对象的创建方式
字面量方式,可动态添加属性和方法, 但无法批量生产对象
Object 内置构造函数的方式 可动态添加属性和方法, 但添加属性和方法时无法批量添加
通过工厂函数的方式
自定义构造函数的方式
      // 创建对象方式
      // 1. 通过字面量的方式   可动态添加属性和方法, 但无法批量生产对象
      var obj1 = {
        name: 'mm',
        age: 18,
        show: function () {
          console.log('i am obj1---show')
        },
      }
      var obj2 = {
        name: 'tt',
        age: 20,
        show: function () {
          console.log('i am obj2---show')
        },
      }
      // 可动态添加属性和方法
      obj1.sex = '女'
      obj2.sex = '男'
      obj1.run = function () {
        console.log('i can run!!!!!---obj1')
      }
      obj2.run = function () {
        console.log('i can run!!!!!---obj2')
      }
      // 2. Object 内置构造函数的方式  可动态添加属性和方法, 但添加属性和方法时无法批量添加
      var obj3 = new Object()
      obj3.name = 'qq'
      obj3.age = 21
      obj3.show = function () {
        console.log('i am obj3---show')
      }
      // 3. 通过工厂函数的方式
      // (1) 创建一个工厂函数
      function factory(name, age) {
        // 手动创建对象
        var obj4 = {}
        obj4.name = name
        obj4.age = age
        obj4.show = function () {
          console.log('i am obj4---show')
        }
        // 手动返回对象
        return obj4
      }
      // (2) 使用工厂函数创建对象
      var obj5 = factory("aa", 18)
      var obj6 = factory("zz", 19)
      var obj7 = new Factory()
      console.log('5---',obj5);
      console.log('6---',obj6);
      console.log(obj5 == obj6);  //false  两个对象类似但不相同
      // 4. 自定义构造函数的方式
      // (1) 自定义函数就是在造机器
      // (2) 构造函数会自动的创建并返回对象,无需return(创建对象时,需要与new关键字配合使用)
      // (3) 手动添加属性和方法
      function Factory(name,age){
        // 手动向对象中添加属性和方法
        // this指当前对象, 动态变化, 指向调用者
        this.name = name
        this.age = age
        this.show = function(){
          console.log('i am' +  obj + '---show');
        }
      }
      // 创建对象   new 构造函数名()   首字母大写,为了区分构造函数
      var obj7 = new Factory("ww",17)
      var obj8 = new Factory("ss",16)
      console.log('7---',obj7);
      console.log('8---',obj8);
      // 访问属性
      console.log(obj7.name); // ww
 创建对象方法比较
将方法写在构造函数内部:
   将方法写在构造函数的原型上:
   - 构造函数
 
构造函数
能批量生产对象
可像函数一样传递参数, 可以为每一个对象添加不同的内容
当需要完成一个功能时, 造一个构造函数, 利用构造函数来创建完成功能的对象
'机器'即为构造函数, 属性就直接写在构造函数内部,方法写在构造函数的原型上(避免每创建一次对象就创建一次相同的函数,造成空间的浪费)开发过程,即为造'机器'的过程, 就是面向对象的封装过程
      // 创建对象 Date是一个制造机器, new Date()创建一个对象, 使用对象来获取年份,月份等
      var time1 = new Date()
      var time2 = new Date()
      console.log(time1 == time2);  //false    每个对象类似,但不相同
      var point = { 
        x:10,
        y: 20,
        function(){
          console.log('point---function');
        }
      }
      console.log(point.x);
 普通函数和自定义构造函数的比较
普通函数: 使用时函数调用[函数名()], 函数名小驼峰式命名规则
自定义构造函数: 用来创建对象[new 函数名()],使用时必须与new连用,否则不能自动创建对象,函数名大驼峰式命名规则(所有单词首字母大写, 与普通函数做区分)
使用构造函数的问题
问题: 如果将方法写在构造函数的内部, 在每次创建对象时,都会创建函数,造成空间浪费
解决: 方法只创建一次, 供所有对象使用, 使用原型
      // 自定义Dog的构造函数
      function Dog(name, type) {
        // 定义属性
        this.name = name
        this.type = type
        // 定义方法
        this.print = function () {
            console.log('dogName: ', this.name, ', type:', this.type)
        }
      }
      // 创建对象(生产实例)
      var dog1 = new Dog('小白', '萨摩耶')
      var dog2 = new Dog('小黑', '二哈')
      console.log('dog1: ',dog1, 'dog2: ', dog2);
      // 调用print方法
      dog1.print()
      dog2.print()
      // dog1和dog2不是相同的对象
      console.log(dog1 === dog2); //false
      // dog1和dog2的print方法不同, 是两个函数
      console.log(dog1.print === dog2.print); //false
      /*   dog1 第一次使用new Dog创建的对象 会将this指向dog1, 将构造函数中的代码全部执行一遍(在dog1上添加name和type属性, 同时也在dog1上添加print方法,创建一个函数)
            dog2 第二次使用new Dog创建的对象 会将this指向dog2, 将构造函数中的代码全部执行一遍(在dog2上添加name和type属性, 同时也在dog1上添加print方法,创建一个函数)     */ 
 - this关键字
 
this指向问题
普通函数函数中,this指向函数调用者
this指向window对象(全局)
箭头函数中,this指向函数定义时this的指向(通常函数定义时指向的是window)
      // this指向问题
      // 1. this指向当前调用者
      var obj9 = {
        a: 10,
        b: 20,
        show: function(){
          console.log(this);   // this指向obj9
          return this.a   
        }
      }
      console.log(obj9.show());  //10
      // 2. this指向 Window 对象 (当前调用者为window)
      var a = 30  //全局变量
      var show1 = obj9.show  //不加() 获取到show函数
      console.log(show1);   
      show1()   //等价于window.show(), show中的this指向全局的Window对象, 返回的是全局变量a=30的值
 改变this指向
call() 方法 fun.call(thisArg, arg1, arg2, ...) 调用一个对象(可调用函数)
apply()方法 fun.apply(thisArg, [argsArray]) 可调用函数, 可改变函数的 this 指向, 参数必须为数组形式 [argsArray]
bind()方法 fun.bind(thisArg, arg1, arg2, ...)不会调用函数, 可以改变函数内部this指向
- 原型
 
原型
在js中的每一个函数都有一个属性 prototype(原型对象),是一个对象
每个对象上都有一个 __proto__(对象原型)属性, 指向所属构造函数的prototype
当访问对象的属性或方法时, 首先在自身查找, 若没有,则会在 __proto__上查找
在原型上添加方法, 在内存中只会创建一个方法, 专门供对象使用
构造函数constructor: 本身也是函数,故也有prototype属性
   /*        在js内部,所有的object对象数据类型都属于内置构造函数Object
          在js内部,所有函数都属于内置构造函数Function对象    */
 /*  问题1: cat对象上的__proto__指向谁?
             -> cat 所属的构造函数是 Cat
             -> cat.__proto__ 指向 Cat.prototype
      问题2: Cat.prototype上的__proto__指向谁?
             -> Cat.prototype 是一个对象, 也有__proto__属性
             -> Cat.prototype所属的构造函数是Object
             -> Cat.prototype.__proto__指向 Object.prototype
      问题3: Cat的__proto__指向谁? 
             -> Cat是一个自定义构造函数, 本事也是一个对象, 故也有__proto__属性
             -> Cat 的所属构造函数是 Function  (在js内部,所有函数都属于内置构造函数Function对象)
             -> Cat.__ptoto__ 指向 Function.prototype
      问题4: Object.prototype上的__proto__指向谁?
             -> Object.prototype 是一个对象, 也有__proto__属性
             -> Object.prototype在js中是顶级原型对象,不存在__proto__对象原型
             -> Object.prototype.__proto__ 指向 null
      问题5: Object上的__proto__指向谁?
             -> Object对象有__proto__属性
             -> Object是一个内置构造函数, 故所属构造函数是 Function
             -> Object.__proto__指向 Function.prototype
      问题6: Function.prototype上的__proto__指向谁?
             -> Function.prototype 是一个对象, 也有__proto__属性
             -> Function.prototype 所属构造函数是 Object
             -> Function.prototype.__proto__ 指向 Object.prototype
      问题7: Function上的__proto__指向谁?
             -> Function 是一个对象, 也有__proto__属性
             -> Function 是一个内置构造函数, 所属的构造函数就是Function 
             -> Function.__proto__ 指向 Function.prototype
  */
     function Cat(name, type) {
        // 定义属性
        this.name = name
        this.type = type
      }
      // Cat.prototype会得到一个对象, 是Cat构造函数的原型
      Cat.prototype.print = function(){
        console.log('CatName: ', this.name, ', Cattype:', this.type)
      }
      var cat1 = new Cat('小白', '小橘猫')
      var cat2 = new Cat('小黑', '英短')
      console.log(cat1, cat2);
      console.log(cat1 === cat2); //false
      console.log(cat1.print === cat2.print); //true
      console.log(Cat.prototype); //{print: ƒ, constructor: ƒ}
      // 问题1: cat.__proto__ 指向 Cat.prototype
      console.log(cat1.__proto__ ) //{print: ƒ, constructor: ƒ}
      console.log(cat1.__proto__ === Cat.prototype);  //true
      // 问题2: Cat.prototype.__proto__指向 Object.prototype
      console.log(Cat.prototype.__proto__ );  //  {constructor: ƒ, __defineGetter__: ƒ, …}
      console.log(Cat.prototype.__proto__ === Object.prototype);  //true
      // 问题3: Cat.__ptoto__ 指向 Function.prototype
      console.log(Cat.__proto__);  //ƒ () { [native code] }
      console.log(Cat.__proto__ === Function.prototype);  //true
      // 问题4: Object.prototype.__proto__ 指向 null
      console.log(Object.prototype.__proto__);  // null
      // 问题5: Object.__proto__指向 Function.prototype
      console.log(Object.__proto__ );  // ƒ () { [native code] }
      console.log(Object.__proto__ === Function.prototype);  // true
      // 问题6: Function.prototype.__proto__ 指向 Object.prototype
      console.log(Function.prototype.__proto__);  //{constructor: ƒ, __defineGetter__: ƒ, …}
      console.log(Function.prototype.__proto__ === Object.prototype);  //true
      // 问题7: Function.__proto__ 指向 Object.prototype
      console.log(Function.__proto__ );  //  ƒ () { [native code] }
      console.log(Function.__proto__ === Function.prototype);  //true
      console.log( function(){} instanceof Object);  //true  函数也是一个对象
      console.log(Object instanceof Object);  //true  函数也是一个对象
 原型链
原型链是用__proto__属性穿起来的链状结构
   原型上的属性
      var obj1 = {
        a: 100,
        b: 200,
        getA :function() {
          return this.a
        },
      }
      var obj2 = {
        a: 300,
        b: 400,
        getA :function() {
          return this.a
        },
      }
      console.log(obj1.getA());  //100
      console.log(obj1.getA.apply(obj2)); //300 使得obj1.getA中的this指向obj2 
      // 添加原型上的属性
      Object.prototype.c = 600  
      // hasOwnProperty() 检测是否属于自身属性
      console.log(obj1.hasOwnProperty('a'));  // true
      console.log(obj1.hasOwnProperty('c'));  // false   c属性在原型上,不属于自身属性
      // 遍历对象  
      // 可获取到原型上的属性值
      for(var key in obj1){
        console.log(obj1[key]);   // 100 200  ƒ(){return this.a } 600 
      }
      // Object.keys() 无法获取到原型上的属性
      console.log(Object.keys(obj1));  //['a', 'b', 'getA']
 
 PreviousNotes:
https://blog.csdn.net/qq_54379580/article/details/126464151


















