【JavaScript】对象的分类

189 阅读1分钟

一、构造函数

实例

写一段代码,输出一个正方形的周长和面积

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

输出多个正方形的周长和面积

let square1 = {
	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
    }
}

...//这种方法写起来太累

使用循环

squareList = []
for(let i=0;i<12;i++){
	let squareList[i] = {
		width:5,
    	getArea(){  //函数getArea会被重复创建11次
    		return this.width * this.width
    	},
    	getLength(){  //函数getLength会被重复创建11次
    		return this.width * 4
    	}
    }
}

这是一段浪费内存的代码

借助原型

squareList = []
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]
}

但是,代码过于分散

将创建squareList[n]的过程写成一个函数

squareList = []
widthList = [5,6,5,6,5,6,5,6,5,6,5,6]
function createSquare(width){ //这个函数叫做构造函数
	let obj[width] = Object.create(squarePrototype) //以 squarePrototype 为原型创建一个空对象
    obj[width].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()是分散的

将原型放到函数中(使函数和原型可以互相查找)

squareList = []
widthList = [5,6,5,6,5,6,5,6,5,6,5,6]
function createSquare(width){ //这个函数叫做构造函数
	let obj[width] = Object.create(createSquare.squarePrototype) //以 squarePrototype 为原型创建一个空对象
    obj[width].width = width
    return obj
}
let 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)
}

使用new操作符,函数和原型结合

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

每个函数都有 prototype 属性
每个 prototype 都有 constructor 属性

总结

new X() 做了哪些事情

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

构造函数X

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

举例

Dog(name)

function Dog(name){
	this.name = name 
    this.color = 'white'
    this.kind = 'bixiong'
}

Dog.prototype.talk = function(){console.log('talking')} 
Dog.prototype.run = function(){console.log('running')}

let dog1 = new Dog('Jack')
let dog2 = new Dog('Lucky')

注意事项

大小写

  • 所有构造函数(专门用于创建对象的函数),首字母大写
  • 所有被构造出来的对象,首字母小写

词性

  • new 后面的函数,使用名词,如 new Person()、new Object()
  • 其他函数,一般使用动词开头,如 createSquare()、createElement('div')

二、对象的原型和构造函数的关系

原型公式

对象._proto_ === 构造函数.prototype

小练习

第一个

let x = {}
1、x的原型是什么? 答:Object.prototype === x._proto_
2、x.__proto__的值是什么? 答:window.Object.prototype的地址

第二个

let square = new Square(5)
1、square的原型是什么? 答:Square.prototype

第三个

1、Object.prototype 是哪个函数构造的? 答:它没有父母,是个根对象。
2、Object.prototype 的原型是? 答:Object.prototype._proto_ === null,根对象没有原型,值是null。

三、对象的分类

为什么对象需要分类?

  • 很多对象拥有相同的属性,它们属于同一类
  • 对象也有不同的属性,需要将它们归为不同的类,比如Array、Function属于不同的类,Object创建出来的对象是最没有特点的对象

类型和类的区别

类型

JS数据的分类,四基两空一对象,共7种:number、string、bool、symbol、null、undefined、object

  • 针对对象的分类,有无数种
  • 常见的:Array、Function、Date、RegExp

数组对象

定义

  • let arr = [1,2,3]
  • let arr = new Array(1,2,3)
  • let arr = new Array(3)

自身属性

  • [1,2,3]的自身属性:'0'、'1'、'2'、'length'

共有属性

  • arr._proto_ 中的所有属性,比如'push'、'pop'、'shift'、'unshift'、'join'...
  • arr._proto_._proto_ === Object.prototype,数组对象的原型的原型即obj对象的原型

函数对象

定义

  • function fn(x,y){return x+y}
  • let fn = function fn(x,y){return x+y}
  • let fn = (x,y) => x+y
  • let fn = new Function('x','y','return x+y')

自身属性

'name'/'length'/'prototype',函数自带一个prototype属性

共有属性

'call'/'apply'/'bind'

四、JS的终级问题

window是什么构造的?

window是Window构造的
window.constructor === Window,返回true

window.Object是什么构造的

window.Function,所有函数对象都是它构造的

window.Function是什么构造的

window.Function,浏览器构造了Function并指定它的构造者是自己

五、类class

class写法

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

prototype写法

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