js对象分类

126 阅读3分钟
  • 构造函数是用来创建对象的,首字母大写;普通函数小写

prototype 指向一块内存,这个内存里面有共用属性
proto 指向同一块内存
prototype 和 _*proto* _ 的不同点在于
prototype 是构造函数的属性,而 proto 是对象的属性
难点在于……构造函数也是对象!
如果没有 prototype,那么共用属性就没有立足之地
如果没有 proto,那么一个对象就不知道自己的共用属性有哪些。


  • 问:设置一个小程序:输出各种形状的面积和周长

    答:1. 函数和原型结合

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

  1. 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)
}
// 多美,几乎没有一句多余的废话

// 每个函数都有 prototype 属性,这是 JS 之父故意的
// 每个 prototype 都有 constructor 属性,也是故意的
  • new X() 自动做了四件事情
自动创建空对象
自动为空对象关联原型,原型地址指定为 X.prototype
自动将空对象作为 this 关键字运行构造函数
自动 return this
  • 构造函数 X
X 函数本身负责给对象本身添加属性
X.prototype 对象负责保存对象的共用属性
  • 代码规范
  1. 大小写
所有构造函数(专门用于创建对象的函数)首字母大写
所有被构造出来的对象,首字母小写
  1. 词性
new 后面的函数,使用名词形式
如 new Person()、new Object()
其他函数,一般使用动词开头
如 createSquare(5)、createElement('div')
其他规则以后再说
  • 总结一个重要的公式(也是 JS 里唯一的一个公式): 你是谁构造的你的原型就是谁的 prototype 属性对应的对象
    即:对象.proto === 其构造函数.prototype
let obj = new Object() 的原型是 Object.prototype
let arr = new Array() 的原型是 Array.prototype

Square 最终版

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

Circle 需求

function Circle(radius){ 
  this.radius = radius
}
Circle.prototype.getArea = function(){ 
  return Math.pow(this.radius,2) * Math.PI  
}
Circle.prototype.getLength = function(){
  return this.radius * 2 * Math.PI
}
let circle = new Circle(5)
circle.radius
circle.getArea()
circle.getLength()

Rectangle 需求

function Rect(width, height){ 
  this.width = width
  this.height = height
}
Rect.prototype.getArea = function(){ 
  return this.width * this.height  
}
Rect.prototype.getLength = function(){
  return (this.width + this.height) * 2
}
let react = new Rect(4,5)
rect.width
rect.height
rect.getArea()
rect.getLength()

JS 终极一问

window 是谁构造的?
Window
可以通过 constructor 属性看出构造者

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

window.Function 是谁构造的?
window.Function
因为所有函数都是 window.Function 构造的
自己构造的自己?并不是这样,这是「上帝」的安排
浏览器构造了 Function,然后指定它的构造者是自己

类型 & 类

类:针对对象的分类:Array,Function,Date,RegExp
类型:js数据分类:8种

ES6引入了class语法

//重写Square
class Square{
  static x = 1
  width = 0
  constructor(width){
    this.width = width
  } 
  getArea(){ 
    return this.width * this.width 
  }
  getLength(){
    return this.width * 4
  }
  get area2(){ // 只读属性
    return this.width * this.width
  }
}
//重写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 Circle(5)
circle.radius
circle.getArea()
circle.getLength()
//重写Rect
class Rect{
  constructor(width, height){ 
    this.width = width
    this.height = height
  }
  getArea(){ 
    return this.width * this.height  
  }
  getLength(){
    return (this.width + this.height) * 2
  }
}
let react = new Rect(4,5)
rect.width
rect.height
rect.getArea()
rect.getLength()

拓展

prototype能更好的理解js内存本质,class也好用但不易理解js本质

__proto__和prototype存在的意义

ES 6 新特性列表

【小试牛刀】

//分别用 Person构造函数 和 class ,要求以下代码运行通过: 

class Person {
    你来补全代码
}

let person = new Person('frank', 18)
person.name === 'frank' // true
person.age === 18 // true
person.sayHi() // 打印出「你好,我叫 frank」

let person2 = new Person('jack', 19)
person2.name === 'jack' // true
person2.age === 19 // true
person2.sayHi() // 打印出「你好,我叫 jack」

【答案1.1】

function Person(person,person2){
this.person = person
this.person2 = person2
}

let person = new Person('frank', 18)
person.name === 'frank' // true
person.age === 18 // true
person.sayHi =function(){console.log('你好,我叫 frank')}
person.sayHi() // 打印出「你好,我叫 frank」

let person2 = new Person('jack', 19)
person2.name === 'jack' // true
person2.age === 19 // true
person2.sayHi =function(){console.log('你好,我叫jack')}
person2.sayHi() // 打印出「你好,我叫 jack」

【答案1.2】

function Person(name,age){
    this.name = name
    this.age = age
}

Person.prototype.sayHi = function(){
    console.log('你好,我叫 ' + this.name)
}

let person = new Person('frank', 18)
person.name === 'frank' // true
person.age === 18 // true
person.sayHi() // 打印出「你好,我叫 frank」

let person2 = new Person('jack', 19)
person2.name === 'jack' // true
person2.age === 19 // true
person2.sayHi() // 打印出「你好,我叫 jack」

【答案2】

class Person{
constructor(name, age){
this.name = name
this.age = age
}

sayHi(){
    console.log('你好,我是'+this.name)
    }
}

let person = new Person('frank', 18)
person.name === 'frank' // true
person.age === 18 // true
person.sayHi() // 打印出「你好,我叫 frank」

let person2 = new Person('jack', 19)
person2.name === 'jack' // true
person2.age === 19 // true
person2.sayHi() // 打印出「你好,我叫 jack」