JS类

229 阅读5分钟

以下代码:

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

正方形拥有三个属性:边长、面积、周长。 如果需要多个类似的正方形的话,则需要分类。

代码如下:

let squareList = []
for(let i = 0; i < 12 ; i++){
    squareList[i] = {
        width: 5,
        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,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,5,6]
function createSquare(width){ //此函数叫构造函数
    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,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开发者直接用呢?于是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
} //所有的JS里面的函数,从它出生就带有一个叫prototype的属性,这个属性内有constructor属性,指向函数自身
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属性,也是故意的

new X()自动做了四件事

  • 自动创建空对象
  • 自动为空对象关联原型,原型地址指定为X.prototype
  • 自动将空对象作为this关键字运行构造函数
  • 自动return this
  • 构造函数X
  • X函数本身负责给对象本身添加属性
  • X.prototype对象负责保存对象的公共属性

代码规范: 大小写:

  • 所有构造函数(专门用于创建对象的函数)首字母大写
  • 所有备构造出来的函数,首字母小写 词性:
  • new后面的函数,使用名次形式
  • new Person()new Object()
  • 其他函数,一般使用动词开头
  • createSquare(5)createElement('div')

重要公式:

你是谁构造的,你的原型就是谁的prototype属性对应的对象

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

请问:

  1. Object.prototype是那个函数构造出来的?
  2. Object.prototype的原型是什么?
  3. Object.prototype.__proto__? null

最终版代码(存疑)

function Square(width){
    this.width = width
}
Square.prototype.getArea = function(){
    rutuen this.width * this.width
}
Square.prototype.getLength(){
    return this.width * 4
}
let square = new Square(5)
square.width
square.getArea()
square.getLength()

对象需要分类,不同的对象有不同的功能。 理由一:

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

理由二:

  • 但是还有很多对象拥有其他的属性和行为
  • 所以就需要不同的分类
  • 比如:Square /Circle / Rect 就是不同的分类
  • Array / Function也是不同的分类
  • Object创建出来的对象,是最没有特点的对象

类型和类的区别:

-类型是JS数据的分类,有7种

  • 四基两空一对象
  • 类是针对于对象的分类,有无数种
  • 常见的有ArrayFunctionDateRegExp

数组对象

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

数组对象的共用属性

  • 'push' / 'pop' / 'shift'(提档,提出数组最前面元素,将其删掉,返回该值) / 'unshift'(压档,添加新元素,返回新长度) / 'join'()

【注意下标是字符串,不是数字,length遍历不到】

函数对象

  • 定义一个函数
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'

终极一问:

  1. window是谁构造的
  • Window
  • 可以通过constructor属性看出构造者
  1. window.Object是谁构造的
  • window.Function
  • 因为所有函数都是window.Function构造的
  1. window.Function是谁构造的
  • window.Function
  • 因为所有函数都是window.Function构造的
  • 自己构造自己?并不是这样,这是「上帝」的安排
  • 浏览器构造了Function,然后指定它的构造者是自己

class语法

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

同时class还引入了更多概念

class Square{
    static x = 1
    width = 0     //初始化width
    constructor(width){
        this.width = width
    }
    getArea(){
        return this.width * this.width
    }
    getLength(){
        return this.width * 4
    }
    get area2(){    //只读属性
        return this.width * this.width
    }
}
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 Circle(5)

circle.radius
circle.radius()
circle.getLength()
class Rect{
    constrcutor(width,height){
        this.width = width
        this.height = height
    }
    getArea(){
        return this.width * this.height
    }
    getLength(){
        return (this.width + this.height)
    }
}
let react = new Rect(4,5)
rect.width
rect.height
rect.getArea()
rect.getLength()