JavaScript对象

133 阅读7分钟

一、对象的基本使用

1.1 认识对象类型

  • 对象类型是一种存储键值对(key-value)的复杂数据类型

    • 对象类型可以使用{…}来创建的复杂类型,里面包含的是键值对(“key: value”)
    • 键值对可以是属性和方法(在对象中的函数称之为方法
    • 其中key是字符串(也叫做属性名property name ,ES6之后也可以是Symbol类型,后续补充)
    • 其中value可以是任意类型,包括基本数据类型、函数类型、对象类型等
    // key: 字符串类型, 但是在定义对象的属性名时, 大部分情况下引号都是可以省略的
    var person = {
      // key: value
      name: "kobe",
      age: 24,
      height: 1.98,
      "friend": {
        name: "james",
        age: 30
      },
      run: function() {
        console.log("running")
      },
      eat: function() {
        console.log("eat foods")
      },
      study: function() {
        console.log("studying")
      }
    }
    

1.2 对象的创建方式

  • 对象的创建方法有很多,包括三种:

    • 对象字面量(Object Literal):通过 {}
    • new Object+动态添加属性
    • new 其他类
    // 1.对象字面量
    var obj1 = {
      name: "why"
    }
    
    // 2.new Object()
    // // Object构造函数
    var obj2 = new Object()
    obj2.name = "kobe"
    
    // 3.new 其他类()
    function Person() {}
    var obj3 = new Person()
    

1.3 对象的操作过程

  • 获取属性
  • 修改属性
  • 新增属性
  • 删除属性
    • delete 删除操作符

      // 1.定义了一个对象
      var info = {
        name: "kobe",
        age: 20,
        friend: {
          name: "james",
          age: 30
        },
        running: function() {
          console.log("running~")
        }
      }
      
      // 2.访问对象中的属性
      // console.log(info.name)
      // console.log(info.friend.name)
      // info.running()
      
      // 3.修改对象中的属性
      // info.age = 25
      // info.running = function() {
      //   alert("I am running~")
      // }
      // console.log(info.age)
      // info.running()
      
      // 4.添加对象中的属性
      info.height = 1.88
      info.studying = function() {
        console.log("I am studying~")
      }
      console.log(info)
      
      // 5.删除对象中的属性
      // delete关键字(操作符)
      delete info.age
      delete info.height
      console.log(info)
      

1.4 方括号的用法

  • 点符号要求 key有效的变量标识符

    • 不包含空格,不以数字开头,也不包含特殊字符(允许使用 $ 和 _)
  • 对于特殊的属性可以使用方括号访问:

    • 方括号在定义或者操作属性时更加的灵活
    var obj = {
      name: "kobe",
      "my friend": "james",
      "eating something": function() {
        console.log("eating~")
      }
    }
    
    console.log(obj["my friend"])
    // 以下两种写法一样
    console.log(obj.name)
    console.log(obj["name"])
    
    // obj["eating something"]()
    var eatKey = "eating something"
    obj[eatKey]()
    

1.5 对象的遍历方式

  • 对象的遍历(迭代):表示获取对象中所有的属性和方法。

    • Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组
  • 普通for循环

  • for in 遍历方法

    var info = {
      name: "kobe",
      age: 24,
      height: 1.98
    }
    
    // console.log(Object.keys(info))
    
    // 对对象进行遍历
    // 1.普通for循环
    var infoKeys = Object.keys(info)
    for (var i = 0; i < infoKeys.length; i++) {
      var key = infoKeys[i]
      var value = info[key]
      console.log(`key: ${key}, value: ${value}`)
    }
    
    // 2.for..in..: 遍历对象
    for (var key in info) {
      var value = info[key]
      console.log(`key: ${key}, value: ${value}`)
    }
    
    // 对象不支持:  for..of..: 默认是不能遍历对象
    // for (var foo of info) {
    // }
    

二、内存分配

2.1 内存概念理解

  • 栈内存 / 堆内存

    • 原始类型占据的空间是在栈内存中分配
    • 对象类型占据的空间是在堆内存中分配
  • 值/引用类型的分配

    • 原始类型的保存方式:在变量中保存的是值本身,所以原始类型也被称之为值类型
    • 对象类型的保存方式:在变量中保存的是对象的 “引用”,所以对象类型也被称之为引用类型

    image.png

2.2 一些现象的内存表示

  • 两个对象的比较

    两个对象的比较.png

  • 引用赋值

    image.png

  • 值传递

    image.png

  • 引用传递,在函数中创建了一个新对象,没有对传入对象进行修改

    image.png

  • 引用传递,对传入的对象进行修改

    image.png

三. this的使用

3.1 this到底指向什么

  • 目前掌握两个 this 的判断方法:

    • 默认的方式调用一个函数,this指向window
    • 通过对象调用,this指向调用的对象
    // 函数中是有一个this的变量, this变量在大多数情况下会指向一个对象
    // arguments保存的是传入的所有参数
    
    // 情况一: 如果普通的函数被默认调用, 那么this指向的就是window
    function foo(name, age) {
      console.log(arguments)
      console.log(this)  // window
    }
    foo("abc", 123)
    
    function sayHello(name) {
      console.log(this)  // window
    }
    
    
    // 情况二: 如果函数它是被某一个对象来引用并且调用它, 那么this会指向这个对象(调用的那个调用)
    var obj = {
      name: "zhangsan",
      running: function() {
        console.log(this) // obj对象
        // console.log(obj)
        // console.log(this === obj) // true
      }
    }
    obj.running()
    
    // 1.题目一:
    var fn = obj.running
    fn() // window
    
    // 2.题目二:
    function bar() {
      console.log(this) // obj对象
    }
    var obj = {
      name: "why",
      bar: bar
    }
    obj.bar()
    
  • 后续补充其他 this 规律

3.2 this的作用

  • 方便在一个方法中,拿到当前对象的一些属性

    var info = {
      name: "zhangsan",
      age: 38,
      running: function() {
        console.log("running~", this.name)
      },
      eating: function() {
        console.log("eating~", this.name)
      },
      studying: function() {
        console.log("studying~", this.name)
      }
    }
    
    info.running()
    info.eating()
    info.studying()
    

四、面向对象-创建一系列对象

4.1 对象字面量

  • 弊端: 重复代码

    // 一系列的学生对象
    // 重复代码的复用: for/函数
    var stu1 = {
      name: "zhangsan",
      age: 18,
      height: 1.88,
      running: function() {
        console.log("running~")
      }
    }
    var stu2 = {
      name: "lisi",
      age: 22,
      height: 1.98,
      running: function() {
        console.log("running~")
      }
    }
    var stu3 = {
      name: "wangwu",
      age: 20,
      height: 1.77,
      running: function() {
        console.log("running~")
      }
    }
    

4.2 工厂函数

  • 封装一个函数,这个函数用于帮助创建一个对象,创建一系列对象只需要重复调用这个函数即可

  • 工厂模式其实是一种常见的设计模式

  • 问题:

    • 在打印对象时,对象的类型都是Object类型,从某种角度来说,这些对象应该有一个他们共同的类型
    // 工厂函数(工厂生产student对象) -> 一种设计模式
    // 通过工厂设计模式, 自己来定义了一个这样的函数
    function createStudent(name, age, height) {
      var stu = {}
      stu.name = name
      stu.age = age
      stu.height = height
      stu.running = function() {
        console.log("running~")
      }
      return stu
    }
    
    var stu1 = createStudent("zhangsan", 18, 1.88)
    var stu2 = createStudent("lisi", 22, 1.98)
    var stu3 = createStudent("wangwu", 20, 1.77)
    console.log(stu1)
    console.log(stu2)
    console.log(stu3)
    

4.3 构造函数

  • 什么是构造函数?

    • 构造函数也称之为构造器(constructor),通常是我们在创建对象时会调用的函数
    • 在其他面向的编程语言里面,构造函数是存在于类中的一个方法,称之为构造方法
    • 但是JavaScript中的构造函数有点不太一样,构造函数扮演了其他语言中类的角色
  • new操作符:

    1. 在内存中创建一个新的对象(空对象)
    2. 这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性(后续会补充)
    3. 构造函数内部的this,会指向创建出来的新对象
    4. 执行函数的内部代码(函数体代码)
    5. 如果构造函数没有返回非空对象,则返回创建出来的新对象
    // JavaScript已经默认提供给了我们可以更加符合JavaScript思维方式(面向对象的思维方式)的一种创建对象的规则
    // 在函数中的this一般指向某一个对象
    function coder(name, age, height) {
      this.name = name
      this.age = age
      this.height = height
      this.running = function() {
        console.log("running~")
      }
    }
    
    // 在函数调用的前面加 new 关键字(操作符)
    var stu1 = new coder("zhangsan", 18, 1.88)
    var stu2 = new coder("lisi", 30, 1.98)
    

4.4 类和对象的关系

  • 在JavaScript中,构造函数其实就是类的扮演者:
    • 构造函数也称之为构造器(constructor),通常是我们在创建对象时会调用的函数
    • 比如系统默认给我们提供的Date就是一个构造函数,也可以看成是一个
    • 在ES5之前,我们都是通过function来声明一个 构造函数(类) 的,之后通过 new 关键字来对其进行调用
    • 在ES6之后,JavaScript可以像别的语言一样,通过 class 来声明一个类
  • 关系
    • 类是一系列的描述/图纸
      • 应该具备属性/行为
    • 对象是根据类,具体创建出来的
    image.png
  • 编程范式: 面向对象的编程范式

4.5 构造函数的使用

  • JavaScript中的构造函数是怎么样的?
    • 构造函数也是一个普通的函数,从表现形式来说,和千千万万个普通的函数没有任何区别
    • 如果这么一个普通的函数被使用 new 操作符来调用了,那么这个函数就称之为是一个构造函数
  • 构造函数的使用大驼峰(首字母会大写)

    // 创建一系列的对象
    // 构造函数的名称: 使用大驼峰
    function Person() {
    
    }
    
    var p1 = new Person()
    console.log(p1)
    
    // 平时创建普通的对象
    // new Object()
    var obj1 = {}
    var obj2 = new Object()
    var obj3 = new Person()
    
    // 普通函数: 使用小驼峰
    function sayHello() {
    
    }
    
  • 构造函数还有很多其他的特性(后续补充)
    • 原型、原型链、实现继承的方案
    • ES6中类、继承的实现

五、对象的补充

5.1 全局对象window

  • 作用一: 查找变量时, 最终会window头上

  • 作用二: JavaScript/浏览器默认提供一些变量/函数/类, 提供到window中

  • 作用三: var定义变量会被添加到window上

    // 浏览器中存在一个全局对象object -> window
    console.log(window)
    
    // 使用var定义变量
    var message = "Hello World"
    
    function foo() {
      // 自己的作用域
      // abc()
      // alert("Hello World")
      console.log(window.console === console) // true
    
      // 创建一个对象
      // var obj = new Object()
      console.log(window.Object === Object) // true
    
      // DOM
      console.log(document)
    
      // window.message
      console.log(window.message)
    }
    foo()
    

5.2 函数也是一个对象类型

// 定义原始类型的变量
var name = "kobe"
var age = 18

// 定义对象类型的变量
// 地址 - 指针 - 引用
var obj = {} // 堆内存
var foo = function() {} // 堆内存
function bar() {} // 堆内存

console.log(typeof obj) // object
console.log(typeof foo) // function -> object

// var stu = new Student() // stu是一个Student -> Person

// 引申一些别的知识
var info = {}
info.name = "abc"

function sayHello() {
}
sayHello.age = 18
console.log(sayHello.age)

function Dog() {

}
// 构造函数上(类上面)添加的函数, 称之为类方法
Dog.running = function() {}
Dog.running()