JavaScript对象分类

397 阅读1分钟

目录:

1. 构造函数

2. 数组对象

3. 函数对象

4. ES6函数新语法class

一、构造函数

  • 构造函数就是可以构造对象的函数,用一个例子来说明

1.假如需要写一个程序,通过正方形的边长计算周长和面积

  • 代码如下
let square = {
    width:5,
    getArea(){
        return this.width * this.width; // 求面积公式
    },
    getLength(){
        return this.width * 4 // 求周长公式
    }
}

2.假如需要很多正方形,那么新手会把上面代码重复很多遍

  • 代码如下
let square1 = {
    width: 5,
    getArea(){
        return this.width * this.width
    },
    getLength(){
        return this.width * 4 
    }
}

let square2 = {
    width: 5,
    getArea(){
        return this.width * this.width
    },
    getLength(){
        return this.width * 4 
    }
}

 let square3 = { ...
  • 这样写显得很蛋疼,还不容易改参数

3.所以我们申明一个边长数据的数组,通过for循环i遍历长度

  • 代码如下
let squareList = []
for(let i = 0; i<12; i++){
    squareList[i] = {
        width:5,
        getArea(){
            return this.width * this.width
        },
        getLength(){
            return this.width * 4
        }
    }
}

4.万一不是所有正方形的边长都相等呢,边长5和6交替出现怎么办

  • 代码如下
let squareList = []
let widthList = [5,6,5,6,5,6,5,6,5,6,5,6]
for(let i = 0; i<12 ; i++){
    squareList[i] = {
        width: widthList[i],
        getArea(){
            return this.width * this.width
        },
        getLength(){
            return this.width * 4
        }
    }
}
  • 上司会说你这啥垃圾代码,太占内存,性能太差,拿去优化

5.所以我们为了不让相同的函数被for一遍一遍的新建内存,我们把相同函数封装到原型里

  • 代码如下
let squareList = []
let widthList =[5,6,5,6,5,6,5,6,5,6,5,6]
let squarePrototype = {
    getArea(){
        return this.width * this.widthList
    },
    getLength(){
        return this.width * 4
    }
}
for(let i = 0; i<12 ; i++){
    squareList[i] = Object.create(squarePrototype)
    squareList[i].width = widthList[i]
}
  • 这样确实解决了问题,但是原型和正方形太分散了,没有体现是一体的

6.所以我们把创建原型对象和正方形对象的过程放到一个函数里

  • 代码如下
let squareList = []
let widthList = [5,6,5,6,5,6,5,6,5,6,5,6]

function createSquare(width){ // 把原型放到函数上
    let obj = Object.create(createSquare.squarePrototype)
    obj.width = width
    return obj
}
createSquare.squarePrototype = {
    getArea(){
        return this.width * this.width
    },
    getLength(){
        return this.width * 4
    },
    constructor: createSquare//方便通过原型找到构造函数
}
for(let i =0; i<12; i++){
    squareList[i] = createSquare(widthList[i])
    console.log(squareList[i].constructor)
    //可以知道谁构造了这个对象
  • 这样确实很方便,所以JS之父创造了new

7.通过new关键词和this重写代码

  • 代码如下
let squareList5 = []
let widthList5 = [5,6,5,6,5,6,5,6,5,6,5,6]

function Square(width){
    this.width = width
}

Square.prototype.getArea = function(){ // 这里不能直接重写prototype是因为其本身里面有属性,如果重写会把原来属性覆盖
    return this.width * this.width
}

Square.prototype.getLength = function(){
    return this.width * 4
}

for(let i = 0; i<12; i++){
    squareList5[i] = new Square(widthList5[i])
    console.log(squareList[i].constructor);
}

new关键词和this

  • 所有js函数自带prototype属性

  • prototype属性里的constructor属性里的值,等于该函数自身

  • 这样写几乎没有一句废话

总结

  • new X()自动做了四件事

    1. 自动创建了空对象

    2. 自动为空对象关联原型,原型地址指定为X.prototype

    3. 自动将空对象作为this关键字运行构造函数

    4. 自动return this

  • 构造函数X

    1. X函数本身负责给对象本身添加属性

    2. X.prototype 对象负责保存对象的共有属性

代码规范

  • 大小写

    1. 所有构造函数(专门用来创建对象的函数)首字母大写

    2. 所有被构造出来的对象,首字母小写

  • 词性

    1. new后面的函数,使用名词形式

    2. new person()/ new object

    3. 其他函数,一般使用动词开头

    4. createSquare(5)/ createElement('div')

二、如何确定一个对象的原型

  • 代码如下

    1. let obj = new Object() 原型是Object.prototype

    2. let arr = new Array() 原型是Array.prototype

    3. let square = new Square() 的原型是 Square.prototype

    4. let fn = new Function() 的原型是 Function.prototype

  • 因为 new 操作符,就是这么设计的

    • new为这个对象,关联了原型地址为x.prototype
  • 结论

    • 你是谁构造的,你的原型就是谁的prototype

原型公式

  • 对象.__proto__ === 其构造函数.prototype

三、对象需要分类

理由1

  • 有很多对象拥有一样的属性和行为

  • 需要把它们分为同一类

  • 比如 square1square2

  • 这样创建类似对象的时候就很方便

理由2

  • 但是还是有很多对象拥有其他的属性和行为

  • 所以就需要不同的分类

  • 比如 square(正方形)/circle(圆形)/rect(长方形)/就是不同的分类

  • Array/Function 也是不同的分类

  • 而Object创建出来的对象,是最没有特点的对象

类型和类

  • 类型

    1. 类型是JS数据的分类,有七种

    2. 四基两空一对象

    1. 类是针对与对象的分类,有无数种

    2. 常见的有ArrayFunctionDateRegexp

四、对象分类的介绍

1. 数组对象

  • (1) 定义一个数组对象

    • let arr = [1,2,3]

    • let arr = new Array(1,2,3) 元素为1,2,3

    • let arr = new Array(3) 数组长度为3

  • (2) 数组对象自身属性

    • '0'/'1'/'2'/'length'

    • 注意:数组属性名没有数字,只有字符串

  • (3) 数组对象的共用属性

    • 'push'/'pop'/'shift'/'unshift'/'join'

    • 其实就是英语对应的意思结合到属性内就是作用,用法都在MDN

    • 后面会详细的学习

2. 函数对象

  • (1) 定义一个函数对象

    • function fn(x,y){return x+y}

    • let fn2 = function fn(x,y){return x+y}

    • let fn = (x,y) => x+y

    • let fn = new Function('x','y','return x+y')

  • (2) 函数对象自身属性

    • 'name'/'length'
  • (3) 函数对象共用属性

    • 'call'/'apply'/'bind'

    • 后面会详细的学习

五、JS终极思考

1. window是谁构造的

  • Window 构造的

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

2. window.Object 是谁构造的

  • window.Function

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

3. window.Function是谁构造的

  • window.Function

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

  • 浏览器构造了Function,然后指定它的构造者是自己

六、ES6函数新语法class

  • 把上面的原型代码用class语法改一下
let squareList6 = []
let widthList6 = [5,6,5,6,5,6,5,6,5,6,5,6]

class Square{
    constructor(width){
        this.width = width
    }
    getArea(){
        return this.width * this.width
    }
    getLength(){
        return this.width * 4
    }
}

for(let i = 0; i<12; i++){
    squareList[i]= new Square(widthList[i])
    console.log(squareList[i].constructor)
}
  • class语法引入了更多概念

b6c81dc1dd9fabff38f69f5986d4897.png