对象(object)到底是什么?

  • 对象是单个实物的抽象。
    • e.g. : 一本书、一辆汽车、一个人都可以是对象
    • 当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。
  • 对象是一个容器,封装了属性(property)和方法(method)。
    • 属性是对象的状态
    • 方法是对象的行为(完成某种任务)。
      • 比如,我们可以把动物抽象为 animal 对象,使用“属性”记录具体是哪一种动物,使用“方法”表示动物的某种行为(奔跑、捕猎、休息等等)。

构造函数(constructor)

JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。

  • 每个函数都有 **prototype** 属性
  • 每个 **prototype** 对象都有 **constructor** 属性
  • 每个 **constructor** 属性的值都是它的函数自身
    1. function P() {}
    2. P.prototype.constructor === P // true
    constructor 属性的作用:是可以得知某个实例对象,到底是哪一个构造函数产生的。

什么是构造函数?

构造函数作为对象的模板。就是专门用来生成实例对象的函数。

  • 可以构造出对象的函数

代码规范:

  • 大小写

    • 所有构造函数(专门用于创建对象的函数)首字母大写
    • 所有被构造出来的对象,首字母小写
      1. function Dog(){} // Dog 首字母大写
      2. let dog1 = new Dog() // dog1 首字母小写
  • 词性

  • new 后面的函数(构造函数),使用名词形式
    • 如 new Person()、new Object()
  • 其他函数,一般使用动词开头
    • 如 createSquare(5)、createElement(‘div’)
  • 其他规则以后再说

    let arr1 = new Array() 能接受几个参数?

    • 如果只传一个参数,let arr1 = new Array(3)
      • 那么表示的就是数组的长度,长度为3的空数组
    • 如果传两个参数,let arr2 = new Array(3,5)
      • 意思就是第一个元素是3,第二个元素是5

new 命令

  • new 命令的作用:就是执行构造函数,返回一个实例对象。 ```javascript var Vehicle = function () { this.price = 1000; };

var v = new Vehicle(); v.price // 1000 // new命令执行时,构造函数内部的this,就代表了新生成的实例对象,this.price表示实例对象有一个price属性,值是1000。

  1. - **new X() 自动做了四件事情**
  2. - 自动创建空对象
  3. - 自动为空对象关联原型,原型地址指定为 X.prototype
  4. - 自动将空对象作为 this 关键字运行构造函数
  5. - 自动 return this
  6. - **构造函数 X**
  7. - `X` 函数本身负责给对象本身**添加**属性
  8. - `X.prototype` 对象负责**保存**对象的共有属性
  9. **如果忘了使用 **`**new**`** 命令,直接调用构造函数会发生什么事?**
  10. - 这种情况下,构造函数就变成了普通函数,并不会生成实例对象。而且由于后面会说到的原因,`this` 这时代表全局对象,将造成一些意想不到的结果。
  11. ```javascript
  12. var Vehicle = function (){
  13. this.price = 1000;
  14. };
  15. var v = Vehicle();
  16. v // undefined
  17. price // 1000
  • 为了保证构造函数必须与 new 命令一起使用的解决办法:
    • 构造函数内部使用严格模式,即第一行加上 use strict。 ```javascript / 加上’use strict’ / function Fubar(foo, bar){ ‘use strict’;
      this._foo = foo; this._bar = bar; }

Fubar() // TypeError: Cannot set property ‘_foo’ of undefined

由于严格模式中,函数内部的 this 不能指向全局对象,默认等于undefined, 导致不加new 调用会报错(JavaScript 不允许对undefined添加属性)。

  1. 函数与原型结合,写**正方形**示例:
  2. ```javascript
  3. /* 代码1 */
  4. let squareList = []
  5. let widthList = [5,6,5,6,5,6,5,6,5,6,5,6]
  6. function createSquare(width){
  7. let obj = Object.create(createSquare.squarePrototype)
  8. obj.width = width
  9. return obj
  10. }
  11. createSquare.squarePrototype = { //把原型放到函数上
  12. getArea(){
  13. return this.width * this.width
  14. },
  15. getLength(){
  16. return this.width * 4
  17. },
  18. constructor: createSquare //方便通过原型找到构造函数
  19. }
  20. for(let i = 0; i<12; i++){
  21. squareList[i] = createSquare(widthList[i])
  22. console.log(squareList[i].constructor)
  23. // constructor 可以知道谁构造了这个对象:你妈是谁?
  24. }

用构造函数简化代码1

  1. function Square(width){
  2. this.width = width
  3. }
  4. Square.prototype.getArea = function(){
  5. return this.width * this.width
  6. }
  7. Square.prototype.getLength = function(){
  8. return this.width * 4
  9. }
  10. let square = new Square(5)
  11. square.width
  12. square.getArea()
  13. square.getLength()

圆形

  1. function Circle(radius){
  2. this.radius = radius
  3. }
  4. Circle.prototype.getArea = function(){
  5. return Math.pow(this.radius,2) * Math.PI
  6. }
  7. Circle.prototype.getLength = function(){
  8. return this.radius * 2 * Math.PI
  9. }
  10. let circle = new Circle(5)
  11. circle.radius
  12. circle.getArea()
  13. circle.getLength()

长方形

  1. function Rect(width, height){
  2. this.width = width
  3. this.height = height
  4. }
  5. Rect.prototype.getArea = function(){
  6. return this.width * this.height
  7. }
  8. Rect.prototype.getLength = function(){
  9. return (this.width + this.height) * 2
  10. }
  11. let react = new Rect(4,5)
  12. rect.width
  13. rect.height
  14. rect.getArea()
  15. rect.getLength()

class 语法

ES 6 引入了新语法:class

到底有多少新语法

用 class 重写 Square

  1. class Square{
  2. static x = 1 // static的意思是 x属性是 Square的,要用x时只需 Square.x
  3. width = 0 // 初始化 this.width
  4. constructor(width){
  5. this.width = width
  6. }
  7. getArea(){
  8. return this.width * this.width
  9. }
  10. getLength(){
  11. return this.width * 4
  12. }
  13. get area2(){ // 只读属性
  14. return this.width * this.width
  15. }
  16. }

用 class 重写 Circle

  1. class Circle{
  2. constructor(radius){
  3. this.radius = radius
  4. }
  5. getArea(){
  6. return Math.pow(this.radius,2) * Math.PI
  7. }
  8. getLength(){
  9. return this.radius * 2 * Math.PI
  10. }
  11. }
  12. let circle = new Circle(5)
  13. circle.radius
  14. circle.getArea()
  15. circle.getLength()

用 class 重写 Rect

  1. 代码
  2. class Rect{
  3. constructor(width, height){
  4. this.width = width
  5. this.height = height
  6. }
  7. getArea(){
  8. return this.width * this.height
  9. }
  10. getLength(){
  11. return (this.width + this.height) * 2
  12. }
  13. }
  14. let react = new Rect(4,5)
  15. rect.width
  16. rect.height
  17. rect.getArea()
  18. rect.getLength()

class 中两种函数写法的区别

  1. 语法1
  2. class Person{
  3. sayHi(name){}
  4. }
  5. //等价于
  6. function Person(){}
  7. Person.prototype.sayHi = function(name){}
  8. 语法2:注意冒号变成了等于号
  9. class Person{
  10. sayHi = (name)=>{} // 注意,一般我们不在这个语法里使用普通函数,多用箭头函数
  11. }
  12. // 等价于
  13. function Person(){
  14. this.sayHi = (name)=>{}
  15. }

不要强求完全转换成 ES5

  • 大部分 class 语法都可以转为 ES5 语法,但并不是 100% 能转
  • 有些 class 语法意思理解就行,不需要强行转换为 ES5。

对象为什么需要分类

  • 理由一
    • 有很多对象拥有一样的属性和行为,需要把它们分为同一类,创建类似对象的时候就很方便
      • 如 square1 和 square2
  • 理由二
    • 还有很多对象拥有其他的属性和行为,就需要不同的分类
      • 比如 Square / Circle / Rect 就是不同的分类
      • Array / Function 也是不同的分类
    • Object 创建出来的对象,是最没有特点的对象

类型 V.S. 类

  • 类型
    • 类型是 JS 数据的分类,有 7 种:
    • 四基两空一对象
    • 类是针对于对象的分类,有无数种
    • 有特点的类常见的有 Array、Function、Date、RegExp 等

数组对象

  • 定义一个数组

    1. let arr = [1,2,3]
    2. let arr = new Array(1,2,3) // 元素为 1,2,3
    3. let arr = new Array(3) // 长度为 3
  • 数组对象的自身属性

    • ‘0’ / ‘1’ / ‘2’ / ‘length’
    • 【注意】属性名没有数字,只有字符串
  • 数组对象的共用属性
    • 'push' / 'pop' / 'shift' / 'unshift' / 'join'
    • 用法都在 MDN

函数对象

  • 定义一个函数

    1. function fn(x,y){return x+y} // function,函数,参数,函数体
    2. let fn2 = function fn(x,y){return x+y} // 赋值语句
    3. let fn = (x,y) => x+y // 箭头函数 参数->值
    4. let fn = new Function('x','y', 'return x+y') // new Function
  • 函数对象自身属性

    • 'name' / 'length'
  • 函数对象共用属性
    • 'call' / 'apply' / 'bind'

JS 终极一问

window 是谁构造的

  • Window
  • 可以通过 constructor 属性看出构造者

    window.Object 是谁构造的

  • window.Function

  • 因为所有函数都是 window.Function 构造的

    window.Function 是谁构造的

  • window.Function

  • 因为所有函数都是 window.Function 构造的
  • 浏览器构造了 Function,然后指定它的构造者是自己

属性名和属性值是两个概念

image.png

问:

  • let square = new Square(5)

    1. square 的原型(square.__proto__ 的值)是什么?
    • Square.prototype
  • Object.prototype 是哪个函数构造出来的?

    • 不知道,它没有父母
  • Object.prototype 的原型是什么?
    • 根对象没有原型
  • Object.prototype.proto
    • null

原型公式