JavaScript对象
对象的基本使用
4.1. 认识对象类型
 // key: 字符串类型, 但是在定义对象的属性名时, 大部分情况下引号都是可以省略的
    var person = {
      // key: value
      name: "why",
      age: 18,
      height: 1.88,
      "my friend": {
        name: "kobe",
        age: 30
      },
      run: function() {
        console.log("running")
      },
      eat: function() {
        console.log("eat foods")
      },
      study: function() {
        console.log("studying")
      }
    }
4.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()
4.3. 对象的操作过程
- 获取属性
 - 修改属性
 - 新增属性
 - 删除属性
- delete
 
 
    // 1.定义了一个对象
    var info = {
      name: "why",
      age: 18,
      friend: {
        name: "kobe",
        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)
4.4. 方括号的用法
- 为什么需要使用方括号呢?
- 这是因为点符号要求 key 是有效的变量标识符
 - 不包含空格,不以数字开头,也不包含特殊字符(允许使用 $ 和 _);
 
 
 var obj = {
      name: "why",
      "my friend": "kobe",
      "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]()
4.5. 对象的遍历方式
- 普通的for循环
 - Object.keys()方法会返回一个由一个给定对象的自身可枚举属性组成的数组;
 - for...in...
 - for...of...(不支持):默认是不能遍历对象
 
  var info = {
      name: "why",
      age: 18,
      height: 1.88
    }
    // 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) {
    // }
内存分配
5.1. 内存概念理解
栈内存
- 原始类型占据的空间是在栈内存中分配的;
 
堆内存
- 对象类型占据的空间是在堆内存中分配的;
 

原始类型的保存方式:
- 在变量中保存的是值本身
 - 所以原始类型也被称之为值类型;
 

- 对象类型的保存方式:
- 在变量中保存的是对象的“引用”
 - 所以对象类型也被称之为引用类型;
 
 

5.2. 现象的内存表示
 // var num1 = 123
    // var num2 = 123
    // console.log(num1 === num2)
    // 1.现象一: 两个对象的比较
    // var obj1 = {}
    // var obj2 = {}
    // console.log(obj1 === obj2)
    
    // // 2.现象二: 引用的赋值
    // var info = {
    //   name: "why",
    //   friend: {
    //     name: "kobe"
    //   }
    // }
    // var friend = info.friend
    // friend.name = "james"
    // console.log(info.friend.name) // james
    // 3.现象三: 值传递
    // function foo(a) {
    //   a = 200
    // }
    // var num = 100
    // foo(num)
    // console.log(num) // 100
    // 4.现象四: 引用传递, 但是在函数中创建了一个新对象, 没有对传入对象进行修改
    // function foo(a) {
    //   a = {
    //     name: "why"
    //   }
    
    // }
    var obj = {
      name: "obj" 
    }
    foo(obj)
    console.log(obj)
    // 5.现象五: 引用传递, 但是对传入的对象进行修改
    function foo(a) {
      a.name = "why"
    }
    var obj = {
      name: "obj"
    }
    foo(obj)
    console.log(obj)
六. this的使用
6.1. this到底指向什么
- 在全局环境下面,this指向window;
 - 通过对象调用,this指向调用的对象;
 
    // 情况一: 如果普通的函数被默认调用, 那么this指向的就是window
    function foo(name, age) {
      console.log(arguments)
      console.log(this)
    }
    // 情况二: 如果函数它是被某一个对象来引用并且调用它, 那么this会指向这个对象(调用的那个调用)
    var obj = {
      name: "why",
      running: function() {
        console.log(this)
        // console.log(obj)
        // console.log(this === obj)
      }
    }
    obj.running()
- 测试题
 
// 考验题目
    // 1.题目一:
    // var fn = obj.running
    // fn() // window
    // 2.题目二:
    function bar() {
      console.log(this) // obj对象
    }
    var obj = {
      name: "why",
      bar: bar
    }
    obj.bar()
6.2. this的作用
- 方便在一个方法中, 拿到当前对象的一些属性
 
var info = {
      name: "why",
      age: 18,
      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()
对象的方式
1.1. 对象字面量
- 弊端: 重复代码
 
// 一系列的学生对象
    // 重复代码的复用: for/函数
    var stu1 = {
      name: "why",
      age: 18,
      height: 1.88,
      running: function() {
        console.log("running~")
      }
    }
    var stu2 = {
      name: "kobe",
      age: 30,
      height: 1.98,
      running: function() {
        console.log("running~")
      }
    }
    var stu3 = {
      name: "james",
      age: 25,
      height: 2.05,
      running: function() {
        console.log("running~")
      }
    }
1.2. 工厂函数
- 一种创建对象的方式:工厂函数
 - 我们可以封装一个函数,这个函数用于帮助我们创建一个对象,我们只需要重复调用这个函数即可;
 - 工厂模式其实是一种常见的设计模式;
 
// 工厂函数(工厂生产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("why", 18, 1.88)
    var stu2 = createStudent("kobe", 30, 1.98)
    var stu3 = createStudent("james", 25, 2.05)
    console.log(stu1)
    console.log(stu2)
    console.log(stu3)
工厂方法创建对象有一个比较大的问题:
我们在打印对象时,对象的类型都是Object类型
但是从某些角度来说,这些对象应该有一个他们共同的类型;
下面我们来看一下另外一种模式:构造函数的方式;
1.3. 构造函数
在ES5之前,我们都是通过function来声明一个构造函数(类)的,之后通过new关键字来对其进行调用;
    // 在函数调用的前面加 new 关键字(操作符)
    var stu1 = new coder("why", 18, 1.88)
    var stu2 = new coder("kobe", 30, 1.98)
    console.log(stu1, stu2)
    alert("Hello")
- 构造函数也是一个普通的函数,从表现形式来说,和千千万万个普通的函数没有任何区别;
 - 那么如果这么一个普通的函数被使用new操作符来调用了,那么这个函数就称之为是一个构造函数;
 
1.4.new操作符做了什么事情
- 如果一个函数被使用new操作符调用了,那么它会执行如下操作:
- 在内存中创建一个新的对象(空对象);
 - 这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性;(后面详细讲);
 - 构造函数内部的this,会指向创建出来的新对象;
 - 执行函数的内部代码(函数体代码);
 - 如果构造函数没有返回非空对象,则返回创建出来的新对象;
 
 
1.5. 构造函数的使用
- 构造函数的使用大驼峰(首字母会大写)
 
对象的补充
2.1. 全局对象window
- 作用一: 查找变量时, 最终会window头上
 - 作用二: JavaScript/浏览器默认提供一些变量/函数/类, 提供到window中
 
alert()
- 作用三: var定义变量会被添加到window上
 
2.2. 函数也是一个对象类型
function foo() {}
var bar = foo // 地址
bar()
bar.message = "Hello World"