创建对象的方式
-
- 字面量的方式
-
- 内置构造函数的方式
-
上述的两种方式都能够帮助我们创建对象, 但是不能帮助我们批量生产对象
-
- 工厂函数模式
- 本质上就是一个函数, 函数内部帮助我们创建一个对象, 然后返回出来
- 将来需要对象的时候, 我们直接调用函数即可
-
- 自定义构造函数
- 本质上也是一个函数, 函数内部会帮助我们创建一个对象, 然后返回出来
- 将来需要对象的时候, 我们直接调用函数即可
自定义构造函数的书写
- 构造函数的函数名 建议首字母大写 (为了和普通函数做一个区分)
- 构造函数将来在调用的时候, 必须和 new 关键字 一起使用 (必须这样写)
- 构造函数内部不需要书写 return
- 如果 手动返回了 基本数据类型, 那么写了和没写一样
- 如果 手动返回了 引用数据类型, 那么写了之后构造函数失效
- 构造函数在使用的时候 内部 的 this 规则和之前的函数不太一样 (重点!!!)
- 因为一个函数要想当成构造函数去使用, 那么必须要和 new 关键字一起使用
- 如果一个函数和 new 关键字一起使用, 那么内部的 this 就指向函数中被创建出来的对象
- 构造函数内部的 this 指向于 函数内部自动创建出来的那个对象
-
构造函数不能使用箭头函数, 因为箭头函数内部没有 this
函数访问原型对象
-
首先要明确一点, 原型是为了解决 构造函数的缺点而存在的, 就是构造函数内声明的函数提取到一个公共的地方
-
我们JS中, 所有的函数一定有一个属性 prototype, 这个属性指向了一个对象, 我们将这个对象称之为 原型对象/原型/原型空间
-
每一个原型对象中一定会有一个属性 constructor, 当前属性的属性值就是说当前原型对象是那个函数的
-
注意点: * 我们可以通过 函数的 prototype 属性获取到这个函数的 原型对象, 获取到这个原型对象后, 我们可以向内部添加一些属性 * 属性的值 没有任何限制, 就和我们向一个普通对象中添加内容一样, 但是我们只推荐向内部书写 函数
* 同时我们也要明确一个点, 就是我们添加的这个数据并不是给构造函数使用, 而是给当前的构造函数的所有实例化对象去使用的 -
对象访问自己构造函数的原型对象
-
每一个对象中 都有一个属性 proto (注意: 前后都是两个下划线, 一共是 四个)
-
这个属性会指向自己当前构造函数的原型对象
-
注意: 我们实例化对象可以通过 proto 获取到原型对象的内容, 但是我们一般不会书写 proto
- 因为这个属性可以省略, 我们可以直接拿 实例化对象去调用当前构造函数的原型对象中的内容
-
万物皆对象
-
对象的一个定义:
- 一种数据类型: { key: value, key2: value2 }
- 一类内容中的一个真实个体
-
在 JS 中 只要是 数组[] 那么就属于 Array 这一类内容中的一个真实个体
-
在 JS 中 只要是 函数function 那么就属于 Function 这一类内容中的一个真实个体
-
在 JS 中 只要是 对象{} 那么就属于 Object 这一类内容中的一个真实个体
-
原型链
-
是关于对象内部属性的查找规则
-
当我们在一个对象内部查找一个属性的时候, 会现在当前对象的自身查找
-
如果找到直接使用并停止查找, 如果没有找到, 那么会去到当前对象的 proto 中继续查找
-
如果找到直接使用并停止查找, 如果没有找到, 那么会继续去当前对象的 proto 中继续查找
-
一直到最顶层的对象 Object.prototype, 还是没有找到, 那么返回一个 undefined
-
-
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHi = function () {
console.log('下午好~~~')
}
const p = new Person('张三', 18)
// console.log(p)
console.log('1. ', p.__proto__ === Person.prototype)
console.log('2. ', Person.__proto__ === Function.prototype)
console.log('3. ', Person.prototype.__proto__ === Object.prototype)
console.log('4. ', Function.__proto__ === Function.prototype)
console.log('5. ', Function.prototype.__proto__ === Object.prototype)
console.log('6. ', Object.__proto__ === Function.prototype)
console.log('7. ', Object.prototype.__proto__, Object.prototype.__proto__ === null)
/**
* 1. p.__proto__ === ???
* p 其实就是一个 实例化对象, 构造函数是 Person
* p.__proto__ === Person.prototype
*
* 2. Person.__proto__ === ???
* Person 是构造函数, 本质上就是一个函数
* 在 JS 中, 只要是一个函数, 那么就是 Function 这个构造函数的 实例化对象
* Person.__proto__ === Function.prototype
*
* 3. Person.prototype.__proto__ === ???
* Person 是一个构造函数, 本质上就是一个函数
* Person.prototype 其实就是一个函数的原型对象 本质上就是一个对象
* 所以 Person.prototype.__proto__ 其实就是指向了一个对象的构造函数的原型对象
* 因为JS 中 对象的构造函数就是 Object
* 所以我们可以得到一个等式 Person.prototype.__proto__ === Object.prototype
*
* 4. Function.__proto__ === ???
* Function 是 JS 中内置的一个构造函数, 本质上就是一个函数
*
* 所以我们现在其实就是在找一个函数的构造函数的原型对象, 因为函数的原型对象是 Function
* Function.__proto__ === Function.prototype
*
* 5. Function.prototype.__proto__ === ???
* Function 内置构造函数, 其实就是一个函数
* Function.prototype 指向了当前构造函数的原型对象, 本质上就是一个对象
*
* 所以我们现在本质上就是在找一个对象的 构造函数的原型对象是谁
*
* Function.prototype.__proto__ === Object.prototype
*
* 6. Object.__proto__ === ???
* Object 是 JS 中 一个内置构造函数, 其实就是一个函数
* 现在就相当于在找一个函数的 构造函数的原型对象
*
* Object.__proto__ === Function.prototype
*
* 7. Object.prototype.__proto__ === ???
* 在 JS 中最顶层的对象就是 Object.prototype, 所以如果再向上找的话, 就找不到任何东西了
* 然后 在 JS 中, 给我们返回了一个数据 null
*
* Object.prototype.__proto__ === null
*/
判断数据类型
- typeof
- 缺点: 引用数据类型判断的时候不太准确
- constructor
-
语法: 数据.constructor === 构造函数
- 我们可以通过 对比他等于那个构造函数, 然后确认他是那个数据类型
-
缺点: undefined 和 null 不能使用
- constructor 其实就是一个对象内部的一个属性, 是有可能被修改的
- instanceof
-
语法: 数据 instanceof 构造函数
-
缺点: undefined 和 null 不能使用
- 引用数据类型, 有可能会被识别对 对象类型
- Object.prototype.toString.call(要判断数据类型的数据)
- 能够判断 JS 中 所有的 数据类型