美文网首页
黑马视频-JavaScript高级 1

黑马视频-JavaScript高级 1

作者: 璎珞纨澜 | 来源:发表于2019-08-26 15:57 被阅读0次

    1. JavaScript 基础介绍

    1.1 JavaScript 是什么?

    • 解释执行:轻量级解释下的,是 JIT 编译型的程序设计语言
    • 语言特点:动态,头等函数(First-class Function)
      • 又称函数是 JavaScript 中的一等公民
    • 执行环境:在宿主环境下(host environment)下运行,浏览器是最常见的 JavaScript 宿主环境
      • 但是在很多非浏览器环境中也是用 JavaScript,例如 node.js
    • 编程范式:基于原型,多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如:函数式编程)编程风格

    JS 分为三个部分

    组成部分 说明
    Ecmascript 描述了该语言的语法和基本对象
    DOM 描述了处理网页内容的方法和接口
    BOM 描述了与浏览器进行交互的方法和接口

    1.2 基本概念

    • 语法
      • 区分大小写
      • 标识符
      • 注释
      • 严格模式
      • 语句
    • 关键字和保留字
    • 变量
    • 数据类型
      • typeof 操作符 -- 获取数据类型
      • Undefined
      • Null
      • Boolean
      • Number
      • String
      • Object
    • 操作符
    • 流程控制语句
    • 函数

    1.3 JavaScript 中的数据类型

    JavaScript 有 5 种简单数据类型:Undefined、Null、Boolean、Number、String 和 1 种复杂数据类型 Object

    基本类型(值类型)

    • Undefined
    • Null
    • Boolean
    • Number
    • String

    复杂类型(引用类型)

    • Object
    • Array
    • Date
    • RegExp
    • Function
    • 基本包装类型
      • Boolean
      • Number
      • String
    • 单体内置对象
      • Global
      • Math

    类型检测

    • typeof
    • instanceof
    • Object.prototype.toString.call()

    值类型和引用类型在内存中的存储方式

    • 值类型按值存储:值类型在栈
    • 引用类型按引用存储:引用类型地址在栈,对象在堆

    值类型复制和引用类型复制

    • 值类型按值复制
    • 引用类型按引用复制

    值类型和引用类型参数传递

    • 值类型按值传递
    • 引用类型按引用传递

    值类型与引用类型的差别

    • 基本类型在内存中占据固定大小的空间,因此被保存在栈内存中
    • 从一个变量向另一个变量复制基本类型的值,复制的是值的副本
    • 引用类型的值是对象,保存在堆内存
    • 包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针
    • 从一个变量向另一个变量复制引用类型的值的时候,复制是引用指针,因此两个变量最终都指向同一个对象

    JavaScript 执行过程

    JavaScript 运行分为两个阶段:

    • 预解析
      • 全局预解析(所有变量和函数声明都会提前;同名的函数和变量函数的优先级高)
      • 函数内部预解析(所有的变量、函数和形参都会参与预解析)
        • 函数
        • 形参
        • 普通变量
    • 执行

    先预解析全局作用域,然后执行全局作用域中的代码。
    在执行全局代码的过程中遇到函数调用就会先进行函数预解析,然后再执行函数内代码。


    2. JavaScript 面向对象编程

    2.1 编程思想

    • 面向过程:所有的事情都是亲力亲为,注重的是过程。
    • 面向对象:提出需求,找对象,对象解决,注重的是结果。
      • 面向对象的编程思想:根据需求,抽象出相关的对象,总结对象的特征和行为,把特征变成属性,把行为变成方法。然后定义(js)构造函数,实例化对象,通过对象调用属性和方法,完成相应的需求。
      • js 不是一门面向对象的语言,是基于对象的语言,js可以模拟面向对象。

    2.2 面向对象的特性

    • 封装:就是代码的封装,把一些特征和行为封装在对象中
    • 继承:类与类之间的关系。js中没有类的概念,js有构造函数的概念,是可以有继承的,js的继承是基于原型的
    • 多态:同一个行为,针对不同的对象,产生了不同的效果

    2.3 创建对象的三种方式

    1. 字面量的方式
    var per1 = {
        name:"小张",
        age:20,
        sex:"男",
        readBook:function(){
            console.log("西游记")
        }
    }
    
    1. 调用系统的构造函数方法
    var per2 = new Object()
    per2.name="小张"
    per2.age=20
    per2.sex="男"
    per2.readBook=function(){
        console.log("西游记")
    }
    

    以上两种方式都是不能确定创建出来的对象是什么类型的

    1. 自定义构造函数
    function Person(name,age,sex){
        this.name = name
        this.age = age
        this.sex =sex
        this.readBook= function () {
            console.log("西游记")
        }
    }
    var per = new Person("小张",20,"男")
    console.log(per instanceof Person)
    

    结果输出 true

    1. 工厂模式创建对象
    function createObejct(name, age, sex) {
        var obj = new Object()
        obj.name = name
        obj.age = age
        obj.sex = sex
        obj.readBook = function(){
            console.log("西游记")
        }
        return obj
    }
    var per1=createObejct("小明",20,"男")
    

    自定义构造函数与工厂模式的共同点与不同点:

    • 共同点:都是函数,都可以创建对象,都可以传入参数
    • 不同点:
      • 工厂模式函数名是小写,自定义构造函数函数名是大写
      • 工厂模式函数内部 new 对象并返回该对象,自定义构造函数内部没有new对象返回
      • 工厂模式 new 之后的对象是当前的对象,自定义构造函数 this 是当前的对象
      • 工厂模式是直接调用函数就可以创建对象,自定义构造函数通过 new 的方式来创建对象

    2.4 构造函数与实例对象之间的关系

    面向对象的思想是:抽象的过程 --> 实例化的过程
    自定义构造函数 --> 使用构造函数实例化对象

    function Animal(name) {
        this.name = name
    }
    var dog = new Animal("大黄")
    console.dir(dog)
    console.dir(Animal)
    
    执行结果
    console.log(dog instanceof Animal) // true
    console.log(dog.constructor == Animal) // true
    console.log(dog.__proto__.constructor == Animal) // true
    console.log(dog.__proto__.constructor == Animal.prototype.constructor) // true
    

    总结:

    1. 实例对象是通过构造函数构建的 --- 创建的过程叫做实例化
    2. 如何判断对象是不是这个数据类型?
    • 通过构造器的方式: 实例对象.构造器 == 构造函数名字
    • 对象 instanceof 构造函数名字
      尽可能用第二种方式来识别,为什么?原型讲完再说

    2.5 原型的引入

    首先我们来看构造函数创建对象带来的问题:

    function Person(name,age,sex){
        this.name = name
        this.age = age
        this.sex = sex
        this.readBook = function () {
            console.log("西游记")
        }
    }
    var per1 = new Person("小张",20,"男")
    var per2 = new Person("小杨",25,"女")
    per1.readBook()
    per2.readBook()
    console.log(per1.readBook == per2.readBook)
    
    执行结果

    为什么 per1 和 per2 的 readBook 不相等呢?是因为使用构造函数每创建一个对象就会开辟一块内存空间,而这个对象指向自己对应的那块内存空间。如果我new了100个对象,那么对应的就有一百块内存空间中有一样的 readBook 方法。这样就开辟了大量的控件,浪费内存。那么我们通过原型来解决这个问题。

    function Person(name,age,sex){
        this.name = name
        this.age = age
        this.sex = sex
    }
    Person.prototype.readBook = function(){
        console.log("西游记")
    }
    var per1 = new Person("小张",20,"男")
    var per2 = new Person("小杨",25,"女")
    per1.readBook()
    per2.readBook()
    console.log(per1.readBook == per2.readBook)
    
    image.png
    • __proto__prototype 都是原型对象,对象的引用指向相同。
    • 实例对象中的属性 __proto__,不是标准的属性,是浏览器使用的。有的浏览器支持,有的浏览器不支持该属性,例如IE8不支持,而火狐和谷歌是支持的。
    • 构造函数中的属性prototype,是标准属性,程序员使用的。
    • 原型的作用:解决数据共享,节省内存空间。

    2.6 构造函数、实例对象和原型对象的关系

    通过下面这张图来解释这三者的关系:


    构造函数、实例对象和原型对象的关系
    • 构造函数可以实例化对象。
    • 构造函数中有一个属性叫prototype,是构造函数的原型对象。
    • 构造函数的原型对象(prototype)中有一个 constructor 构造器,这个构造器指向的就是自己所在的原型对象所在的构造函数。
    • 实例对象的原型对象(__proto__)指向的是该构造函数的原型对象。
    • 构造函数的原型对象中的方法是可以被实例对象直接访问的。

    2.7 利用原型共享数据

    不需要共享的数据写在构造函数中,需要共享的数据写在原型中。

    function Student(name,age,sex){
        this.name = name
        this.age = age
        this.sex = sex
    }
    Student.prototype.major = "计算机"
    Student.prototype.teacher = "王老师"
    Student.prototype.study = function(){
        console.log("学Javascript")
    }
    Student.prototype.readBook = function(){
        console.log("看编程书")
    }
    var stu = new Student("小张",20,"男")
    console.dir(Student)
    console.dir(stu)
    
    执行结果

    上面的代码还可以将 prototype 写成一个对象,但是需要在原型对象中需要手动添加构造器为当前的构造函数:

    function Student(name,age,sex){
        this.name = name
        this.age = age
        this.sex = sex
    }
    Student.prototype = {
        constructor: Student, //需要手动添加构造器
        major: "计算机",
        teacher: "王老师",
        study: function(){
            console.log("学Javascript")
        },
        readBook: function(){
        console.log("看编程书")
        }
    }
    var stu = new Student("小张",20,"男")
    console.dir(Student)
    console.dir(stu)
    

    2.8 原型中的方法是可以相互调用的

    我们知道实例对象的方法是可以相互调用的,像这样:

    function Person(name,age,sex){
        this.name = name
        this.age = age
        this.sex = sex
        this.readBook = function () {
            console.log("西游记")
            this.writeBlog()
        }
        this.writeBlog = function() {
            console.log("写观后感")
        }
    }
    var per = new Person("小张",20,"男")
    per.readBook()
    
    执行结果

    如果把方法定义在原型中,能不能相互调用呢?
    原型中的方法是可以相互调用的。

    function Animal(name,age) {
      this.name=name
      this.age=age
    }
    //原型中添加方法
    Animal.prototype.eat=function () {
      console.log("动物吃东西")
      this.play()
    }
    Animal.prototype.play=function () {
      console.log("玩球")
      this.sleep()
    }
    Animal.prototype.sleep=function () {
      console.log("睡觉了")
    }
    
    var dog=new Animal("小苏",20)
    dog.eat()
    
    执行结果

    2.8 实例对象使用属性和方法层层的搜索

    实例对象的用到的属性或者方法先在实例对象中找,找到了则直接使用,如果在实例对象中找不到就会去实例对象的__proto__指向的构造函数的原型对象 prototype 中找,找到了则使用,如果原型对象也没有就会报错不存在。

    2.9 为内置对象添加原型方法

    我们能否为系统的对象的原型添加方法,这相当于在改变源码。
    比如,我希望字符串中有一个倒序字符串的方法,就可以直接在 String 内置对象的原型对象上添加自己的 myReverse 方法:

    String.prototype.myReverse=function () {
      for(var i=this.length-1;i>=0;i--){
        console.log(this[i]);
      }
    }
    var str="abcdefg"
    str.myReverse()
    

    或者是为 Array 内置对象增加自己的冒泡排序方法:

    Array.prototype.mySort=function () {
      for(var i=0;i<this.length-1;i++){
          for(var j=0;j<this.length-1-i;j++){
              if(this[j]<this[j+1]){
                  var temp=this[j]
                this[j]=this[j+1]
                this[j+1]=temp
              }
          }
      }
    }
    var arr=[100,3,56,78,23,10]
    arr.mySort()
    console.log(arr)
    

    系统内置对象的属性和方法可能不满足现在需求,所以,为了方便开发,可以通过原型的方式加入属性或者方法。

    相关文章

      网友评论

          本文标题:黑马视频-JavaScript高级 1

          本文链接:https://www.haomeiwen.com/subject/ncltectx.html