07-JavaScript面向对象

JavaScript面向对象

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

面向对象的特点

  • 是一种符合人们思考习惯的思想
  • 可以将复杂的事情简单化
  • 将程序员从执行者转换成了指挥者

创建默认对象

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

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

    • 如何给一个对象添加属性: 对象名称.属性名称 = 值;
    • 如果给一个对象添加行为: 对象名称.行为名称 = 函数;
  • 创建对象第一种方式

    let 对象名称 = new    Object();
    对象名称.属性名称 = 值;
    对象名称.行为名称 = 方法;
    
  • 创建对象第二种方式

    let 对象名称 = {};
    对象名称.属性名称 = 值;
    对象名称.行为名称 = 方法;
    
  • 创建对象第三种方式

    let 对象名称 = {
        属性名称:值,
        行为名称:方法;
    }
    

方法和函数区别

  • 函数就是没有和其他的类显示的绑定在一起的,就称之为函数,可以直接调用
  • 方法就是显示的和其他的类显示的绑定在一起的,就称之为方法,只能通过对象来调用
  • 无论是函数还是方法,内部都有一个叫this的东西,谁调用了当前的函数或者方法,那么当前的this就是谁,函数内部的this输出的是window,方法内部的this输出的是当前调用的那个对象

工厂函数不专业

  • 工厂函数就是专门用于创建对象的函数

    function 函数名称(形参列表){
        let 对象名称 = new Object();
        对象名称.属性名称 = 形参;
        对象名称.行为名称 = 方法;
        return 对象名称;
    }
    

构造函数

  • 构造函数和工厂函数一样,都是专门用于创建对象的,本质上是工厂函数的简写

  • 构造函数和工厂函数的区别

    • 构造函数的函数名称首字母必须大写
    • 构造函数只能通过new来调用
    function 构造函数名称(形参列表){
        let 对象名称 = new Object(); //系统自动添加
        let this = 对象名称; //系统自动添加
        this.属性名称 = 形参;
        return this; //系统自动添加
    }
    构造函数名称.prototype = {
        行为名称:方法
    }
    当我们通过new来调用函数时
    1.会在构造函数中自动创建一个对象
    2.会自动将刚才创建的对象赋值给this
    3.会在构造函数最后自动添加return this;
    
    
  • prototype的特点

    • 储存在prototype中的方法可以被对应构造函数创建出来的所有对象共享
    • prototype中除了可以存储方法以外,还可以存储属性
    • prototype中如果出现了和构造函数中同名的属性或者方法,对象在访问的时候,访问到的是构造函数中的数据
  • prototype应用场景

    • prototype中一般情况下用于存储所有对象都相同的一些属性以及方法
    • 如果是对象特有的属性或者方法,我们会存储到构造函数中

对象三角恋关系

  • 每个构造函数中都有一个默认的属性,叫做prototype,prototype属性保存着一个对象,这个对象我们称之为原型对象
  • 每个原型对象都有一个默认的属性,叫做constructor,constructor指向当前原型对象对应的那个构造函数
  • 通过构造函数创建出来的对象称之为实例对象,每个实例对象中都有一个默认的属性,叫做__proto__,__proto__指向创建它的那个构造函数的原型对象

Function函数

  • JavaScript中函数是引用类型(对象类型),既然是对象,所以也是通过构造函数创建出来的,所有函数都是通过Function构造函数创建出来的对象
  • JavaScript中只要是函数就由prototype属性,Function函数的prototype属性指向Function原型对象
  • JavaScript中只要是原型对象就有constructor属性,Function原型对象的constructor指向它对应的构造函数
  • Function构造函数也是一个对象, 所以也有__proto__属性,Function构造函数__proto__属性指向Function原型对象

Object函数

  • JavaScript中还有一个系统提供的构造函数叫做Object,只要是函数都是"Function构造函数"的实例对象
  • 只要是对象就有__proto__属性,所以Object构造函数也有__proto__属性,Object构造函数的__proto__属性指向创建它那个构造函数的原型对象
  • Object原型对象的__proto__属性指向NULL

函数对象完整关系

  • 所有的构造函数都有一个prototype属性, 所有prototype属性都指向自己的原型对象
  • 所有的原型对象都有一个constructor属性, 所有constructor属性都指向自己的构造函数
  • 所有函数都是Function构造函数的实例对象
  • 所有函数都是对象, 包括Function构造函数
  • 所有对象都有__proto__属性
  • 普通对象的__proto__属性指向创建它的那个构造函数对应的"原型对象"
  • 所有对象的__proto__属性最终都会指向"Object原型对象"
  • "Object原型对象"的__proto__属性指向NULL
  • "Function构造函数"的__proto__属性指向自己的"原型对象"

原型链

  • 对象中__proto__组成的链条我们称之为原型链
  • 对象在查找属性和方法的时候,会先在当前对象查找
  • 当前对象找不到想要的,会一次去上一级原型对象中查找
  • 找到Object原型对象都没有找到,就会报错
  • 为了不破坏原型链的关系,在给原型对象赋值时,需要手动添加constructor指向对象的构造函数
  • 属性注意点:在给一个对象不存在的属性设置值的时候,不会去原型对象中查找,如果当前对象没有就会给当前对象新增一个不存在的属性

Js三大特性

封装性

  • 对象的私有变量和函数
    • 默认情况下对象中的属性和方法都是公有的,只要拿到对象就能操作对象的属性和方法
    • 外界不能直接访问的变量和函数就是私有变量和私有函数
    • 构造函数的本质也是一个函数,所以也会开启一个新的作用域,所以在构造函数中定义的变量和函数就是私有变量和函数
  • 封装性就是隐藏实现细节,仅对外公开结构
  • 封装就是将数据隐藏起来,只能用此类的方法才可以读取或者设置数据,不可被外部任意修改,封装是面向对象设计本质将变化隔离,这样降低了数据被误用的可能提高安全性和灵活性

属性方法分类

  • 实例属性/实例方法
    • 在企业开发中通过实例对象访问的属性,就称之为实例属性
    • 在企业开发中通过实例对象调用的方法,就称之为实例方法
  • 静态属性/静态方法
    • 在企业开发中通过构造函数访问的属性,就称之为静态属性
    • 在企业开发中通过构造函数调用的方法,就称之为静态方法

继承性

  • 在企业开发中如果构造函数和构造函数之间的关系是is a关系,那么就可以使用继承来优化代码,来减少代码的冗余度
  • bind-call-apply
    • bind方法作用: 修改函数或者方法中的this为指定的对象, 并且会返回一个修改之后的新函数给我们,bind方法除了可以修改this以外, 还可以传递参数, 只不过参数必须写在this对象的后面
    • call方法作用:修改函数或者方法中的this为指定的对象, 并且会立即调用修改之后的函数,call方法除了可以修改this以外, 还可以传递参数, 只不过参数必须写在this对象的后面
    • apply方法作用:修改函数或者方法中的this为指定的对象,并且会立即调用修改之后的函数,apply方法除了可以修改this以外,还可以传递参数,只不过参数必须通过数组的方式传递
  • js中继承的中级方法
    • 在子类的构造函数中通过call借助父类的构造函数
    • 将子类的原型对象修改为父类的实例对象

多态性

  • 强类型语言与弱类型语言
    • 一般编译型语言都是强类型语言,要求变量的使用要严格符合规定
    • 一般解释型语言都是弱类型语言,不会要求变量的使用要严格符合定义
    • 由于js语言是弱类型语言,所有我们不用过多关注多态
  • 多态是指事物的多种状态
  • 父类型变量保存子类型对象, 父类型变量当前保存的对象不同, 产生的结果也不同,这是多态在编程语言中的体现

ES6类和对象

  • 在ES6之前通过构造函数来定义一个类

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

    class 名称{
      //当我们通过new创建对象的时候,系统会自动调用constructor
        constructor(myName,myAge){
            this.name = myName;
            this.age = myAge;
        }
        //下面一行代码默认会添加到原型对象中
        方法名称(){}
        //静态方法
        static 方法名称(){}
    }
    
  • ES6中如何继承

    • 在子类后面添加extends并指定父类的名称
    • 在子类的constructor构造函数中通过super方法借助父类的构造函数
  • 注意点

    • 在ES6标准中添加实例属性都需要在
    • constructor中添加
    • 在ES6中static只支持定义静态方法不支持定义静态属性

获取对象类型:根据对象名称.constructor.name输出来判断

instanceof关键字:用于判断对象是否是指定构造函数的实例,只要构造函数的原型对象出现在实例对象的原型链中都会返回true

isPrototypeOf属性:用于判断一个对象是否是另一个对象的原型,只要调用者在传入对象的原型链上都会返回true

判断对象属性(会查找原型中):通过"属性名称" in 对象返回的值来判断

判断自身是否拥有某个属性:通过对象.hasOwnProperty("属性名称")返回的值来判断


对象遍历

  • 对象遍历就是依次取出对象中所有的属性和方法
  • 在js中可以通过高级for循环来遍历对象
  • for(let key in 对象)将指定对象中所有的属性和方法的名称取出来依次赋值给key这个变量

对象解构赋值

  • 对象的解构赋值和数组的解构赋值除了符号不一样,其他的一模一样
  • 数组解构使用[],对象解构使用{}
  • 在对象解构赋值中,左边的变量名称必须和对象的属性名称一致,才能解构出数据

深拷贝和浅拷贝

  • 深拷贝:修改新变量的值不会影响原有变量的值,默认情况下基本数据类型都是深拷贝
  • 浅拷贝:修改新变量的值会影响原有的变量的值,默认情况下引用类型都是浅拷贝

数组高级API

  • forEach(遍历数组)

    //创建一个自己的forEach
    Array.prototype.myForEach = function(fn){
      for(let i = 0;i < this.length;i++){
          fn(this[i],i,this)
      }
    }
    //使用自己创建的forEach
    arr.myForEach(function(value,index,array){
      console.log(value)
    })
    
  • findIndex/find(数组查找)

    //创建一个自己的findIndex
    Array.prototype.myFindIndex = function(fn){
      for(let i = 0;i < this.length;i++){
            //找到了就返回索引
          if(fn(this[i],i,this)){
              return i;
          }
      }
        //没找到就返回-1
      return -1;
    }
    //使用自己创建的findIndex
    arr.myFindIndex(function(value,index,array)
    {
      if(value === xxx){
          return true;
      }
    })
    
    //创建一个自己的find
    Array.prototype.myFind = function(fn){
        for(let i = 0;i < this.length;i++){
            //找到了就返回元素
            if(fn(this[i],i,this)){
                return this[i];
            }
        }
        //没找到就返回undefined
        return undefined;
    }
    
  • filter/map

    //创建自己的filter
    Array.prototype.myFilter = function(fn){
        //创建一个新数组+
        let newArr = [];
        for(let i = 0;i < this.length;i++){
            //把符合条件的添加到一个新数组中
            if(fn(this[i],i,this)){
                newArr.push(this[i])
            }
        }
        //返回新数组
        return newArr;
    }
    //使用自己创建的filter
    arr.myFilter(function(value,index,array){
        if(value === xxx){
            return true;
        }
    })
    
    //创建自己的map
    Array.prototype.myMap = function(fn){
        //创建一个同样长度的数组
        let newArr = new Array(this.length);
        //把数组中的元素全部设置为undefined
        newArr.fill(undefined);
        for(let i = 0;i < this.length;i++){
            //把符合条件的替换掉原来的undefined
            if(fn(this[i],i,this)){
                newArr[i] = this[i];
            }
        }
        //返回新数组
        return newArr;
    }
    

  • 数组排序:sort
  • 获取字符串长度: .length
  • 获取某个字符串: [索引]/charAt
  • 字符串查找: indexOf/lastIndexOf/includes
  • 拼接字符串: concat(不推荐)/ +
  • 截取子串: slice/substring/substr
  • 字符串切割: split
  • 是否以指定字符串开头: startsWith
  • 是否以指定字符串结尾: endsWith
  • 字符串模板: ``

基本数据类型和基本包装类型

  • 基本数据类型
    • 字符串类型/数值类型/布尔类型/空类型/未定义类型
    • 通过字面量创建的基本数据类型的数据都是常量
    • 常量是不能被修改的,每次修改或者拼接都是生成一个新的
  • 对象类型的特点
    • 有属性和方法
  • 以前之所以能够访问基本数据类型的属性和方法,是因为在运行时系统自动将基本数据类型包装成了对象类型

三大对象

  • JavaScript中提供三种自带的对象,分别是"本地对象"/"内置对象"/"宿主对象",宿主是指JavaScript运行环境,js可以再浏览器中运行,也可以在服务器上运行(nodejs)
  • 本地对象
    • 与宿主无关,无论在浏览器还是服务器中都有的对象
    • 就是ECMAScript标准中定义的类(构造函数)
    • 在使用过程中需要手动new创建
    • 例如:Boolean,Number,String,Array,Function,Object,Data,RegExp等
  • 内置对象
    • 与宿主无关,无论在浏览器还是服务器中都有的对象
    • ECMAScript已经帮我们创建好的对象
    • 在使用过程中无需手动new创建
    • 例如:Global,Math,JSON
  • 宿主对象
    • 对于嵌入到网页的js来说,其宿主对象就是浏览器,所以宿主对象就是浏览器提供的对象
    • 包含:Window和Document等
    • 所有的DOM和BOM对象都属于宿主对象
  • 自定义对象:我们自己编写的类创建的对象
  • Math内置对象
    • Math.floor() 向下取整
    • Math.ceil() 向上取整
    • Math.round() 四舍五入
    • Math.abs() 绝对值
    • Math.random() 生成随机数
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容