构造函数

看下面的Star构造函数

1
2
3
4
5
6
7
8
9
10
11
12
function Star(uname, age) {
this.uname = uname
this.age = age
this.sing = function() {
console.log("i am singing")
}
}

let ldh = new Star("ldh", 22)
let zxy = new Star("zxy", 23)
ldh.sing()
zxy.sing()

构造函数最大的问题就是:存在浪费内存的问题。

ldhzxy的sing方法都是一样的,但是必须创建两个地址块分别给两个人用

image-20201118100816807

prototype对象

为了解决这个的问题,让所有对象使用同一个函数,节省内存,就需要使用原型

  • 猴枣函数通过原型分配的函数是所有对象共享的。
  • 每个构造函数都有一个prototype属性,用于指向prototype对象,这个对象的所有属性和方法,都会构造函数所拥有

简单来说,原型对象的作用就是:共享方法。

1
2
3
4
5
6
7
8
9
10
11
12
function Star(uname, age) {
this.uname = uname;
this.age = age;
}

Star.prototype.sing = function() {
console.log("i am singing")
}

let ldh = new Star("ldh", 22)
let zxy = new Star("zxy", 23)
console.log(ldh.sing === zxy.sing) // true

一般情况下,把公共属性定义到构造函数里面,公共方法放到原型对象对象上

对象原型__proto__

  • 所有对象都会有一个__proto__只想够高函数的prototype原型对象,致所有我们对象可以使用构造函数的prototype对象的属性和方法,就是因为对象有__proto__属性。

  • __proto__属性和构造函数的prototype是等价的。

  • __proto__的意义就在于为查找对象的属性和方法提供一条查找路线。

    方法的查找规则:先在ldh对象身上是否有sing方法,如果没有,就根据__proto__属性,去对应的原型对象查找

1
2
3
4
5
6
7
8
9
10
11
12
function Star(uname, age) {
this.uname = uname;
this.age = age;
}

Star.prototype.sing = function() {
console.log("i am singing")
}

let ldh = new Star("ldh", 22)
let zxy = new Star("zxy", 23)
console.log(ldh.__proto__ === Star.prototype) // true

原型对象的construtor属性

一般来说,每个prototype对象都有一个constructor属性,用于记录该对象引用于那个构造函数,将原型对象重新指向原来的构造函数。

简单来说,构造函数和原型对象是互相引用的

  • 构造函数通过prototype属性引用到原型对象。
  • 原型对象通过coustructor属性引用到构造函数。

将原型对象从object改成map

因为原型对象本身只会用到点号去获取属性,根据鸭子类型,我们可以将构造函数的prototype属性改成map。但是因为原型对象有一个constructor属性,所以需要另加一个constructor这个key

1
2
3
4
5
6
7
8
9
10
function Star(uname, age) {
this.uname = uname;
this.age = age;
}

Star.prototype = {
constructor : Star,
sing : function(){ console.log("i am singing") },
dance: function(){ console.log("i am dancing") }
}

原型链

image-20201119101332202

原型的this指向

原型的this就是指向实例本身

call函数修改this的指向

1
2
3
4
5
6
7
8
9
10
11
function fn() {
console.log("hello world")
console.log(this)
}

var hyl = {
name: "123"
}

fn.call();
fn.call(hyl); // 改变this的指向,this变成了hyl

子构造函数 继承 父构造函数 的construtor

1
2
3
4
5
6
7
8
9
10
11
12
function Father(uname, age) {
this.uname = uname
this.age = age
}

function Son(uname, age, sex) {
// this指向子构造函数的对象实例
Father.call(this, uname, age)
this.sex = sex
}

var son = new Son("asd",15,"male")

子构造函数 继承 父构造函数 的自定义方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Father(uname, age) {
this.uname = uname
this.age = age
}

Father.prototype.money = function() {
console.log("i am earnMoney")
}

function Son(uname, age, sex) {
Father.call(this, uname, age)
this.sex = sex
}

// Son.prototype指向新的Father实例对象
Son.prototype = new Father();
// 注意要把constructor指回原来的原型对象
Son.prototype.constructor = Son;

Son.protptype.exam = function() {
console.log("i am examing")
}
var son = new Son("asd",15,"male")

image-20201119102924559