JavaScript对象分类

160 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

构造函数

如果我们构建一个正方形,并且边长为5,6,5,6,求出它的面积和边长,可以这样写:

let squareList = [];
let widthList = [5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6];
for (i = 0; i < widthList.length; i++) {
  squareList[i] = {
    width: widthList[i],
    getArea() {
      return this.width * this.width;
    },
    getLength() {
      return this.width * 4;
    },
  };
}

但是这样写会有一个问题,那就是每创建一个squareList,就需要在堆里开辟一个新的内存,然后getArea与getLeng同时也要各占用一个新的内存,那么就会创建24个重复的函数。如果创建12个squareList就需要开辟36个内存空间,且加上squareList本身的空数组占用的空间,以及widthList数组占用的空间,就需要38个内存空间。

image.png 如果把函数放到squareList的原型中呢?我们可以这样写:

let squareList = [];
let widthList = [5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6];
let squarePrototype = {
  getArea() {
    return this.width * this.width;
  },
  getLength() {
    return this.width * 4;
  },
};
for (i = 0; i < widthList.length; i++) {
  squareList[i] = Object.create(squarePrototype);
  squareList[i].width = widthList[i];
}

但这种写法又太分散,怎么办?
函数和原型的结合:

let squareList = [];
let widthList = [5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6];
function createSquare() {
  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 (i = 0; i < widthList.length; i++) {
  squareList[i] = createSquare(widthList[i]);
}

这样写即把原型放在了函数上,又将函数放在原型内。

New操作符

let squareList = [];
let widthList = [5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6];
function Square(width) {
  this.width = width;
}
Square.prototype.getArea = function () {
  return this.width * this.width;
};
Square.prototype.getLength = function () {
  return this.width * 4;
};
for (let i = 0; i < widthList.length; i++) {
  squareList[i] = new Square(widthList[i]);
  console.log(squareList[i].constructor);
}

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

  • 自动创建空对象
  • 自动为创建的空对象关联原型,原型地址指定为X.prototype
  • 自动将空对象作为this关键字运行构造函数
  • 自动return this

构造函数X

  • X函数本身负责给对象本身添加属性。
  • X.prototype对象负责保存对象的共有属性。

对象分类的理由

理由一
有很多对象拥有一样的属性和行为
需要把他们分为同一类
如square1和square2
这样创建类似对象的时候就很方便

理由二
但是也有很多对象拥有其他的属性和行为
所以就需要不同的分类
比如Square/Circle/Rect就是不同的分类
Array和Function也是不同的分类

数组对象

定义一个数组

  • let arr = [1,2,3]
  • let arr = new Array(1,2,3) //元素为1,2,3
  • let arr = new Array(3) //长度为3 数组对象的自身属性
  • '0'/'1'/'2'/'3'/'length'
    注意,属性名没有数字,只有字符串。

数组对象的共有属性 'push'/'pop'/'shift'/'unshift'/'join'

函数对象

定义一个函数

  • 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') 函数对象的自身属性

'name'/'length'

函数对象的共有属性

'call'/'apply'/'bind'

window 是谁构造的

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

window.Object 是谁构造的

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

window.Function 是谁构造的

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