JS 对象的分类,内容包括借助对象需要分类吗、类型和类的区别、原型写代码、考几道题、数组对象、函数对象、JS 终极三问、class 语法。
一、对象需要分类吗
对象需要分类,理由如下: 有很多对象拥有一样的属性和行为,需要把它们分为同一类,如 square1 和 square2,这样创建类似对象的时候就很方便
还有很多对象拥有其他的属性和行为,所以就需要不同的分类,比如 Square / Circle / Rect 就是不同的分类,Array / Function 也是不同的分类,而 Object 创建出来的对象,是最没有特点的对象
二、类型和类的区别
类型是 JS 数据的分类,有 7 种,四基两空一对象
类是针对于对象的分类,有无数种,常见的有 Array、Function、Date、RegExp 等
三、原型写代码
有一个需求:存储 12 个正方形边长并可以随时计算他们的面积和周长
版本 1 -- 用循环搞定
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
}
}
}
垃圾代码,浪费了太多内存
版本 2 -- 将 12 个对象的共用属性放到原型里
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 的代码太分散了!
版本 3 -- 代码抽离到函数(这里开始思维很跳跃,好好理解)
let squareList = []
let widthList = [5,6,5,6,5,6,5,6,5,6,5,6]
function createSquare(width){ // 此函数叫做构造函数
let obj = Object.create(squarePrototype) // 以 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])
// 这下创建 square 很简单了吧!
}
squarePrototype 原型和 createSquare 函数还是分散的,能不能组合在一起
版本 4 -- 函数和原型结合
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) // 先使用后定义?NO
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)
// constructor 可以知道谁构造了这个对象
}
这段代码几乎完美,为什么不固定下来,让每个 JS 开发者直接用呢
版本 5 -- new 操作符 (重写)
let squareList = []
let widthList = [5,6,5,6,5,6,5,6,5,6,5,6]
function Square(width){ // 约定俗成,直接 Square 首字母大写,不用 createSquare
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)
}
// 多美,几乎没有一句多余的废话
// 每个函数都有 prototype 属性,这是 JS 之父故意的
// 每个 prototype 都有 constructor 属性,也是故意的
重写的代码与之前对比:function 不同,this 代表新的对象
小总结
1. new X() 自动做了四件事:
- 自动创建空对象
- 自动为空对象关联原型,原型地址指定为 X.prototype
- 自动将空对象作为 this 关键字运行构造函数
- 自动 return this
2. 构造函数 X
- X 函数本身负责给对象本身添加属性
- X.prototype 对象负责保存对象的共用属性
3. 代码规范
- 大小写:所有构造函数(专门用于创造对象的函数)首字母大写,所有被构造出来的对象,首字母小写
- 词性:new 后面的函数,使用名词形式,如:new Person()、new Object(),其他函数,一般使用动词开头,如:createSquare(5)、createElenent(‘div’)
4. 如何确定一个对象的原型
你是谁构造的,你的原型就是谁的 prototype 属性对应的对象
原型公式:对象.__proto__=== 其构造函数.prototype
参考资料:__proto__和 prototype 存在的意义是什么
四、考几道题
1. 送分题
let x = {}
1. x 的原型是什么?
2. x.__proto__ 的值是什么?
3. 上面两个问题是等价的吗?
4. 请用内存图画出 x 的所有属性
答:1. Object.prototype (对应)的对象
2. x 的原型
3. 等价的
记住,属性名是属性名,属性值是地址呀
2. 角度刁钻题
let square = new Square(5)
1. square 的原型是什么?
2. square.__proto__ 的值是什么?
3. 请用内存图画出 x 的所有属性
答:1. Square.prototype 的对象
2. square 的原型
3. 突破天际题
1. Object.prototype 是哪个函数构造出来的?
2. Object.prototype 的原型是什么?
3. Object.prototype.__proto__?
4. 请用内存图画出上述内容
答:1. 不知道,没有爸爸,没有妈妈,x.__prototype === null
2. 没有原型
3. null
五、数组对象
- 定义一个数组
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'
注意,属性名没有数字,只有字符串
- 数组对象的共用属性
'push' / 'pop' / 'shift' / 'unshift' / 'join' 等等
用法都在 MDN
六、函数对象
- 定义一个函数
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'
七、JS 终极三问
window 是谁构造的?
window.Object 是谁构造的?
window.Function 是谁构造的?
答:1. Window,可以通过 constructor 属性看出构造者
2. window.Function,因为所有函数都是 window.Function 构造的
3. 这是「上帝」的安排,所有函数都是 window.Function 构造的?这唯一是个例外
八、class语法
ES 6 引入了新语法,class 统治天下。重写上述代码如下:
class Square{
constructor(width){
this.width = width
}
getArea(){
return this.width * this.width
}
getLength: function(){
return this.width * 4
}
}
「资料来源:©饥人谷」