详解JavaScript创建对象——构造函数模式

文章目录


一、什么是构造函数?

        在一些面向对象的语言,如Java、C++、PHP中,构造函数是很常见的。在Javascript中构造函数首先是一个普通的函数,它可以使用new操作符来调用,并生成一个特殊类型的对象

例如:

// 构造函数模式为对象定义属性和方法
function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        console.log(this.name);
    }
}
// 使用new操作符为构造函数创建对象
let person_1 = new Person("Nicholas", 29, "Software Engineer");
person_1.sayName();    // Nicholas
let person_2 = new Person("Greg", 27, "Doctor");
person_2.sayName();    // Greg

二、构造函数与普通函数的区别

         构造函数与普通函数唯一的区别就是调用的方式不同。除此之外,构造函数也是函数。任何函数只要使用new操作符调用就是构造函数,而不使用new操作符调用的函数就是普通函数。 

注意:借助面向对象编程语言的特点,为区分构造函数和普通函数,构造函数的名称首字母都是要大写的,非构造函数则以小写字母开头。

1.new

        通过构造函数创建对象,使用了new操作符。通过这种方式调用构造函数会执行以下操作:

  1. 内存中创建一个新对象
  2. 这个新对象内部的 [[Prototype]] 特性被赋值为构造函数的 prototype 属性
  3. 构造函数内部的 this 指向该新对象
  4. 执行构造函数内部的代码(给新对象添加属性
  5. 返回该新对象(如果构造函数返回非空对象的话)

        当未使用new操作符调用,以普通函数的形式调用时,结果会将函数内部的属性和方法添加到window对象在没有明确设置this值的情况下,即作为对象的方法调用或者是使用call()、apply()调用),this始终指向Global对象(在浏览器中是window对象)

例如:

// 构造函数模式为对象定义属性和方法
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function () {
        console.log(this.name);
    }
}
// 使用new操作符为构造函数创建对象
let person = new Person("Nicholas", 29);
person.sayName();    // Nicholas

// 作为普通函数调用,添加到window对象
Person("Greg", 27);
window.sayName();    // Greg

此外:构造函数不一定要写出函数声明的形式,函数表达式也可以表示为构造函数

let Person = function(name, age) {    // 函数表达式形式声明构造函数
    this.name = name;
    this.age = age;
    this.sayName = function () {
        console.log(this.name);
    }
}

let person = new Person("Nicholas", 29);
person.sayName();    // Nicholas

2.new.target

        new.target属性可用以检测一个函数是当做普通函数调用还是通过new关键字当做构造函数调用,前者new.target属性的属性值是undefined,后者new.target属性的属性值是指向构造函数的引用。

例如:

function Foo() {
    if(!new.target) throw "Foo must be called with new";
    console.log("Foo instantialted with new");
}
Foo();  // throws "Foo must be called with new"
new Foo();  // Foo instantialted with new

三、使用构造函数

使用构造函数,意味所有的对象,都可以使用相同的基本结构创建

使用构造函数,意味着创建的对象被明确的标记为构造函数的实例

例如:

function Person(name, age) {
    this.name = name;
    this.age = age;
}
let person = new Person("Nicholas", 29);
let people = {
    name: 'Jeck',
    age: 66
}
console.log(person instanceof Person);    // true
console.log(people instanceof Person);    // false

使用构造函数,意味着我们可以在原型上定义公共方法,供多个实例共享

例如:

function Person(name, age) {
    this.name = name;
    this.age = age;
}
// 原型上定义公共方法,供多个实例共享
Person.prototype.getName = function() {
    return this.name;
}
let person_1 = new Person("Kevin Durant", 34);
let person_2 = new Person("Kyrie Owen", 30);
console.log(person_1.getName());    // Kevin Durant
console.log(person_2.getName());    // Kyrie Owen

四、构造函数的问题

        构造函数的主要问题在于:其内部定义的方法会在每个实例上都创建一遍,对于开头第一个例子而言,person_1和person_2两个对象都有名为sayName()的方法,但该方法却来自不同的实例,因此不同实例上的函数虽然同名,却不相等

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function () {
        console.log(this.name);
    }
}
let person_1 = new Person("Nicholas", 29);
let person_2 = new Person("Greg", 27);
console.log(person_1.sayName == person_2.sayName);    // false

        因此,因为都是做同一件事情,就无需重复创建不同的实例,要解决这个问题,可以把函数定义转移到构造函数外部去

例如:

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = sayName;
}
function sayName() {
    console.log(this.name);
}
let person_1 = new Person("Nicholas", 29);
person_1.sayName();    // Nicholas
let person_2 = new Person("Greg", 27);
person_2.sayName();    // Greg

解析:在这里,sayName()被定义在了构造函数外部,在构造函数内部,sayName属性等同于全局sayName()函数,因为这次sayName属性包含的是一个指向外部函数的指针,所以person_1和person_2共享了定义在全局作用域上的sayName()函数。


总结

        以上就是我对JavaScript构造函数的总结,希望对初学者能有帮助,如有不妥之处请批评、斧正。

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JV_32

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值