zl程序教程

您现在的位置是:首页 >  前端

当前栏目

21·灵魂前端工程师养成-JavaScript对象分类

JavaScript工程师对象前端 分类 21 灵魂 养成
2023-06-13 09:11:06 时间

-曾老湿, 江湖人称曾老大。


-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。


JS对象分类


JS对象需要分类吗?

我们一起来思考一下这个问题,JS对象需不需要分类?

首先我们先做一个小程序,输出各种形状的周长

1.正方形

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

刚才的需求,只是一个正方形,现在我们需要一打正方形... 喝过酒的都知道,一打=12个

代码如下,要么是新人,要么是傻子...

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

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

let square3 = {
  width: 7;
  getArea(){
    return this.width * this.width
  },
  getLength(){
    return this.width * 4
  }
}

let square4 = {
  ...
}

用for循环搞定...

代码如下:

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

那么问题又来了,边长都是5,那我想要第一个是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
    }
  }
}

是不是又搞定了?只能说这个代码很辣鸡,浪费了太多内存...

继续改代码,借助原型

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(let i=0;i<12;i++){
  squareList[i] = Object.create(squarePrototype)
  squareList[i].width = widthList[i]
}

又搞定了,但是...还是辣鸡,你创建的square的代码太分散了


构造函数

继续改代码,抽离到函数

let squareList = []
let widthList = [5,6,5,6,5,6,5,6,5,6,5,6]

//此函数叫做构造函数
function createSquare(width){
//以squarePrototype为原型,创建空对象
  let obj = Object.create(squarePrototype)
  obj.width = width
  return obj
}

let squarePrototype = {
  getArea(){
    return this.width * this.width
  },
  getLength(){
    return this.width * 4
  }
}

for(let i=0;i<12;i++){
  squareList[i] = createSquare(widthList[i])
}

又搞定了,但是...还是辣鸡,squarePrototype原型和createSquare函数还是分散的,能不能组合?

函数和原型结合

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) // contructor 可以知道是谁构造了这个对象:你妈是谁?
}

以上代码,几乎完美...那么每次我们都需要这么优化代码么?

于是乎,JS之父展现出他的父爱,决定把这个函数固定下来,让每个JS开发者直接使用

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<12;i++){
  squareList[i] = new Square(widthList[i])
  console.log(squareList[i].constructor) 
}

多么完美的代码,几乎没有一句废话...

总结:

1.当我们用new 后面接一个 开头字母是大写的函数new X(),自动做了四件事情

1)自动创建空对象 2)自动为空对象关联原型,原型地址为X.prototype 3)自动将空对象作为this关键字运行构造函数 4)自动return this

这就是JS之父的父爱...

2.构造函数X

1)X函数本身负责给对象本身添加属性 2)X.prototype对象负责保存对象的共用属性

JS创建对象的基本形式

function Dog(name){
  this.name = name
  this.color = '黄'
  this.kind = '金毛'
}

// 狗有的共同属性,叫唤
Dog.prototype.jiao = function(){console.log('汪汪')}

// 狗有的共同属性,跑
Dog.prototype.run = function(){console.log('狗在跑')}

// 上面我们就把对象构造好了,接下来我们就可以多创建几只狗
let dog1 = new Dog('大黄')

// 让狗叫
dog1.jiao()
汪汪

//让狗跑
dog1.run()
狗在跑


完成上面的图形

2.圆形

function Circle(radius){
  this.radius = radius
}

Circle.prototype.getLength = function(){
  return this.radius * 2 * Math.PI
}

Circle.prototype.getArea = function(){
  return Math.pow(this.radius,2) * Math.PI
}

let c1 = new Circle(10)

c1.getArea()
c1.getLength()

3.长方形

function Rect(width,height){
    this.width = width;
    this.height = height;
}

Rect.prototype.getArea = function(){
    return this.width * this.height
}

Rect.prototype.getLenght = function(){
    return (this.width + this.height) * 2
}

r1.getArea()
20

r1.getLenght()
18

r1.width
4

r1.height
5

对象需要分类么 很显然,需要。


类型VS类

类型: 1.JS的数据分类,有7种 2.四基两空一对象

类: 1.类是针对于对象的分类,有无数种 2.常见的有Array、Function、Date、RegExp

数组对象


定义一个数组

let arr = [1,2,3]
let arr = new Array(1,2,3) // 元素为1,2,3
let arr = new Array(3) // 长度为3

数组对象自身的属性

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

let arr1 = new Array(1,2,3)

arr1
(3) [1, 2, 3]

Object.keys(arr1)
(3) ["0", "1", "2"]

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


数组共用属性

// push,往数组最右边加入内容
arr1.push(4)
4

arr1
(4) [1, 2, 3, 4]

// pop,把数组最右边的元素弹出来
arr1.pop()
4

arr1
(3) [1, 2, 3]

arr1.pop()
3

arr1
(2) [1, 2]

// shift,把最左边的元素弹出来
arr1
(2) [1, 2]

arr1.shift()
1

arr1
[2]

// unshift,往左边插入一个元素
arr1.unshift(6)
2

arr1
(2) [6, 2]

// join
arr2 = [1,2,3,4]
(4) [1, 2, 3, 4]

arr2.join('曾老湿')
"1曾老湿2曾老湿3曾老湿4"

// 连接两个数组
arr3 = [5,6,7,8]
(4) [5, 6, 7, 8]

arr2.concat(arr3)
(8) [1, 2, 3, 4, 5, 6, 7, 8]

函数对象

在其他编程语言中,函数就是函数,并不是一个对象,但是在JS这门奇葩的语言中,函数时一个对象


定义一个函数对象

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')

函数本身的属性

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

f.name
"anonymous"

f.length
2

共用属性

apply bind call

后面单独介绍...


JS终极一问

1.window是谁构造的?

window.constructor
ƒ Window() { [native code] }

由此可见,window的构造者,是Window

2.window.Object是谁构造出来的?

window.Object.constructor
ƒ Function() { [native code] }

由此可见,window.Object的构造者是Function

3.window.Function是谁构造出来的?

window.Function.constructor
ƒ Function() { [native code] }

由此可见,window.Function的构造者是window.Function...

bull shit,什么鬼,他自己把自己造出来了?

这个问题,就相当于... 先有鸡还是先有蛋,浏览器构造了Function

class语法

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

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

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

看一下上面这段眼熟的代码,非常遗憾,我们说了这么多,某些前端认为,这个代码是过时的,应该学习class

class Square{
  constructor(width){
    this.width = width
  }
  getArea(){
    return this.width * this.width
  }
  getLength: function(){
    return this.width * 4
  } //函数的两种写法,都对
}

ES6引入了以上新的语法,class统治天下...


class语法引入新概念

class Square{

  // 属性是Square后面可以调用,Square.x 即可
  static x = 1
  
  //初始化 width
  width = 0
  
  constructor(width){
    this.width = width
  }
  getArea(){
    return this.width * this.width
  }
  getLength: function(){
    return this.width * 4
  }
  
  //只读属性
  get area2(){
    return this.width * this.width
  }
}

class重写Circle

class Circle{
  constructor(radius){
    this.radius = radius
  }
  getArea(){
    return Math.pow(this.radius,2) * Math.PI
  }
  getLength(){
    return this.radius * 2 * Math.PI
  }
}

let circle = new Cricle(5)
circle.radius
circle.getArea()
circle.getLengthh()

class重写Rect

class Rect{
  constructor(width,height){
    this.width = width
    this.height = height
  }
  getArea(){
    return this.width * this.length
  }
  getLength(){
    return (this.width + this.height) * 2
  }
}

let rect = new Rect(4,5)
rect.width
rect.height
rect.getArea
rect.getLength