这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战」。
ECMAScript 中的构造函数是用于创建特定类型对象的
使用规范
按照惯例,构造函数名称的首字母都是要大写的, 非构造函数则以小写字母开头。这是从面向对象编程语言那里借鉴的,有助于在 ECMAScript 中区分构 造函数和普通函数。
- 首字母大写 首字母大写不是必须的,它只是约定的习惯,但应该这么做。这有助于区分构造函数还是普通函数
- 使用
new运算符调用 这是构造函数与普通函数的唯一区别
function Person() {
this.like = '吃喝玩乐';
console.log('Person', this)
}
Person(); //作为普通函数使用
let instanceObj = new Person(); // 做构造函数使用
console.log(instanceObj)
解释一下上面打印结果,第一行是普通调用函数打印的其内部this值,因为是在全局环境调用的,所以为window
第二行是构造函数被new运算符调用输出的结果,this指向这个创建的实例对象;
第三行打印的就是通过构造函数创建的实例对象了。
注:如果创建实例不需要传参,后面的小括号可加可不加,如下
function Person() {
this.like = '吃喝玩乐';
console.log('Person', this)
}
let obj1 = new Person();
let obj2 = new Person;
上面例子结果是一样的,只要有 new 操作符,就可以调用相应的构造函数。
new一个函数会发生什么?
- 在内存中创建一个新对象。
- 这个新对象内部的
[[Prototype]]特性被赋值为构造函数的 prototype 属性。[[Prototype]]联系着这个对象实例与构造函数的原型对象(而非构造函数)
构造函数的prototype == 指向原型对象的指针\ - 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)。\
- 执行构造函数内部的代码(给新对象添加属性)。\
- 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。
function Person() {
return {
name: 'new一个对象'
}
}
let obj = new Person()
上面例子中,返回了一个对象,obj就是函数内部返回的这个对象。
使用构造函数创建对象的优缺点
-
解决创建多个类似对象的问题 避免创建具有同样接口的多个对象需要重复编写很多代码。
-
解决对象标识问题 新创建的对象是什么类型?
基于这个构造函数创建的对象,其类型就是这个函数,当然每个对象也都是Object的实例。
function Person() {
this.name = 'new一个对象'
}
let obj = new Person()
console.log(obj.constructor == Person); // true
console.log(obj instanceof Person); // true
console.log(obj instanceof Object); // true
问题:定义的方法会在每个实例上 都创建一遍。
对象不止有属性,也会有方法(函数作为某对象的属性值)
// 用构造函数,创建通用方法
function Person() {
this.name = 'new一个对象';
this.sayName = function(){
console.log('一个叫sayName的方法')
}
}
let person1 = new Person()
let person2 = new Person()
console.log(person1.name == person2.name) // true
console.log(person1.sayName == person2.sayName) // false
首先我们知道,js中函数也是个对象,每次通过new创建实例对象,都会创建一个sayName的函数,它们只是名字相同,但不相等。
每创建一个Person实例,sayName就会被重复创建一次;但是sayName内部实现都是一样的,这样每次都要创建一个对象显然不是很好。
解决1:
将sayName提取到构造函数外部
function sayName(){
console.log('一个叫sayName的方法')
}
function Person() {
this.name = 'new一个对象';
this.sayName = sayName;
}
let person1 = new Person()
let person2 = new Person()
console.log(person1.sayName == person2.sayName) // true
解决2:
通过函数原型的方式,函数都有prototype属性(箭头函数除外),将sayName定义在prototype中,所有基于这个函数创建的实例对象都会继承其prototype属性和方法
function Person() {
this.name = 'new一个对象';
}
Person.prototype.sayName = function(){
console.log('一个叫sayName的方法')
}
let person1 = new Person()
let person2 = new Person()
console.log(person1.sayName == person2.sayName) // true
console.log(person1)