- 构造函数是用来创建对象的,首字母大写;普通函数小写
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 可以知道谁构造了这个对象:你妈是谁?
}
- 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 对象负责保存对象的共用属性
- 代码规范
- 大小写
所有构造函数(专门用于创建对象的函数)首字母大写
所有被构造出来的对象,首字母小写
- 词性
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本质
【小试牛刀】
//分别用 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」