创建一个对象的方式中有一个构造函数模式。ECMAScript中的构造函数是用于创建特定类型对象的。如Object和Array这样的原生构造函数,运行时可以直接在执行环境中使用。
还可以自定义构造函数,以函数的形式为自己的对象类型定义属性和方法
如一个构造函数:
function Student(name,age){ this.name = name this.age = age this.show = function(){ console.log(`姓名:${this.name},年龄:${this.age}`); } } let s1 = new Student("XLX",25) s1.show() // 姓名:XLX,年龄:25
注意:
- 构造函数名称首字母大写
- 非构造函数小写字母开头
这里的new关键字做了哪些事:
- new创建了一个空对象;
- 自动设置当前新创建的空对象继承构造函数的原型对象(新对象的__proto__设为构造函数的prototype属性)
- 调用构造函数,并将构造函数中的this统一指向正在创建的这个新对象。(让实参值强行添加到新对象中的对应的属性上);
- 返回新对象的地址保存到变量中
其实,构造函数也是函数,构造函数与普通函数的唯一区别在于调用方式不同。
- 任何函数只要使用new操作符调用就是构造函数,不使用new操作符调用的函数就是普通函数。如上方的Student构造函数:
-
function Student(name,age){ this.name = name this.age = age this.show = function(){ console.log(`姓名:${this.name},年龄:${this.age}`); } } Student("张三",28) window.show()
- 说明:
- 这里直接通过普通函数的方式调用
- 由于在上下文中没有使用严格模式,所以构造函数中的this指向了window(严格模式下this会指向undefined)
- 所以这里通过普通函数的方式调用相当于window.Student("张三",28)
-
构造函数的问题:
主要问题在于:构造函数内的方法会在每个实例上都创建一遍。如上面的Student对象:
function Student(name,age){ this.name = name this.age = age this.show = function(){ console.log(`姓名:${this.name},年龄:${this.age}`); } } let s1 = new Student("张三",24) let s2 = new Student("李四",26) console.log(s1.show === s2.show) // false
每个Student实例都会有一个自己的show方法实例,以这种方式创建函数会带来不同的作用域链和标识符解析。但创建新Function实例的机制是一样的,因此不同实例上的函数虽然同名却不相等
由于做的事情一样,因此没必要定义两个不同的Function实例:
1 function Student(name,age){ 2 this.name = name 3 this.age = age 4 this.show = show 5 } 6 7 function show(){ 8 console.log(`姓名:${this.name},年龄:${this.age}`); 9 } 10 11 let s1 = new Student("张三",24) 12 let s2 = new Student("李四",26) 13 console.log(s1.show === s2.show) // true
说明:
- 这里的show方法相当于全局的函数。因此也是相等的
问题:
- 这里的show方法保存在全局,容易造成全局污染
- 解决:原型模式创建对象