什么是构造函数?
- 一个函数返回是对象,那么这个函数就是构造函数.或者说, 一个函数具备以下特征那么就是构造函数,比如
- 构造函数的函数名的首字母大写
- 在函数体内使用 this 关键字,表示要生成的对象实例,构造函数并不出显示的返回任何值,而是默认返回 #this
- 作为构造函数调用时,必须与new操作符配合使用 ??? (后面详细说明new操作符干了那些事情)
前面我们已经知道了什么是构造函数,接下来让我们看看构造函数还存在那些缺点.
让我们通过代码的形式来看看吧
//构造函数1
function Person(name = "a", age = 18) {
const obj = Object.create(Person.共有属性);
//相当于 obj.隐藏属性 = Person.共有属性
obj.name = name;
obj.age = age;
return obj;
}
Person.共有属性 = {
sayHi() {
console.log(`hi - ${this.name}`);
},
run() {
console.log(`${this.name} is running`);
},
};
const p1 = Person("aliyu", 18); // object类型
console.log(p1);
如何这样子写代码的话那么就会导致创造出来的对象的类型并不符合我们的预期. 如下图所示:
这里的p1是谁构造出来的呢?
console.log(p1.constructor); // ƒ Object() { [native code] }
很遗憾的是这里的类型是Object 那么我们稍微升级下这段代码.
//当我们给前面的
Person.共有属性 = {
constructor: Person, // 最关键的是这一句代码 添加这句话就直接指定了Person构造出来的类型就是Person
}
至此,我们通过明确的显式的指定constructor 构造器就是Person. 但是, 这样的话不是那么的方便, 所以呢, 咱们的JavaScript之父, 说: 既然你们写的这么好,那以后就别写了. 我帮你们内置就完事了. 所以后来才有了 new 关键字来 正如我们经常所说的,new 一个女朋友 一样. 言归正传.
我们再次升级前面的代码:
function Person(name = "a", age = 18) {
this.name = name;
this.age = age;
}
Person.共有属性 = {
constructor: Person,
sayHi() {
console.log(`hi - ${this.name}`);
},
run() {
console.log(`${this.name} is running`);
},
};
const p1 = new Person("aliyu", 18);
console.log(p1);
console.log(p1.constructor); // Person
在 Person里面少写了两行代码, 把 obj 换成了 this . const p1 = new Person("aliyu", 18); 这里换成了 new 关键词. 那可能有很多朋友觉得为啥加了 new 之后就可以了呢. 其实前面我们也有说到, JS之父觉得我们老写那几行代码写多了比较烦,所以当我们new 构造函数的时候 其实就已经做了我们前面所写的那写代码了.
那我们具体谈谈 new 到底做了那么事情呢?
- new 帮你创建一个新对象 const obj = {}
- new 帮你准备了 Person.共有属性 这里面的共有属性其实就是 prototype | 只有函数才会有prototype 这个属性. 普通对象的隐式属性 [[prototype]] |
- new 帮你关联隐藏属性与共有属性 this.proto = Person.prototype
- new 帮你 return 新对象
至此 最新的全部代码就是:
//只写自由属性
function Person(name = '匿名', age = 0) {
this.name = name
this.age = age
}
//只写Person对象的共有属性
Person.prototype = {
constructor: Person,
sayHi() {
console.log(`你好,我是 ${this.name}`)
},
run() {
console.log(`${this.name} 在打篮球🏀`)
}
}
const f1 = new Person('ikun', 18) // ikun yydds
f1.sayHi()
f1.run()
这里引出第一个问题 共有属性一定是函数吗?
在构造函数的形式中不一定非要是函数形式也可以是 属性的方式. 比如
function Person(name = "匿名", age = 1) {
this.name = name;
this.age = age;
}
// 共有属性
Person.prototype.syaHi = function () {
console.log(`你好,我是${this.name},今年${this.age}岁了`);
};
//构造函数方式的共有属性不一定非要是函数
Person.prototype.种族 = "人类";
const p1 = new Person("张三", 20);
p1.syaHi();
console.dir(p1);
但是在 class 形式中 共有属性必须是 函数. 不然 在class 形式下 自动 放入 自由属性中.
自有属性一定不是函数吗?
自由属性也是可以写函数的, 场景就是, 比如 需要使用到 自由属性中的变量的时候.
Person.共有属性 是什么时候创建的?
Person.共有属性(prototype) 在创建 Person 构造函数的时候就已经创建了. 正如前面所说, 只有函数有prototype 相相呼应 .
这里引申出另外一个有意思的问题?
箭头函数不能当构造函数?
箭头函数不可以当构造函数, 因为它不支持 this 、 不自带 prototype .
后来 在 ES6 后加入了class 关键字 写法更简洁更优雅.
// class方式共有属性不可以是非函数
class Person1 {
constructor(name = "匿名", age = 1) {
this.name = name;
this.age = age;
}
sayHi() {
console.log(`你好,我是${this.name},今年${this.age}岁了`);
}
种族 = "人类"; // 这句自动加入到 constructor 里面 this.种族 = "人类"
}
const p2 = new Person1("赵四", 18);
console.dir(p2);
class 写法 还有一个问题就是不可以直接像以前 Person.x = x 随意添加一个属性了. 如果你想添加属性必须 使用 static 关键字
如果要添加私有属性的话 必须使用特殊符号 # 比如 在class中这样使用
class Dog {
#a = 1
constructor(){
//要使用私有属性的话使用this读取
this.a = this.#a
}
}
至此文章结束了, 本文记录本人学习的过程, 可能写的不是很好, 如果有大佬发现里面的错误,还往大佬可以指出. 感谢阅读.