1.使用工厂模式创建
使用特定的函数创建对象。
function createClass(name, age) {
let o = new Object();
o.name = name;
o.age = age;
o.say = function() {
console.log(this.name, this.age)
}
return o;
}
let c = createClass('xxx', 11);
c.say();
函数createClass接收两个参数,然后函数的内部通过这两个参数创建出一个对象返回。
这种创建方式,有个问题,就是不知道内部创建的对象是什么类型的。
2.构造函数创建
使用构造函数模式,可以这样创建对象。
function CustomClass(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log(this.name, this.age);
}
}
let c = new CustomClass('xxx', 11);
c.say();
通过CustomClass()构造函数代替了createClass()工厂函数。实际上内部是一致的,区别在于:
- 1.没有显示的创建对象。
- 2.属性和方法直接赋值给了this。
- 3.没有return。
- 4.函数名首字母大写了,这是一种约定俗成的写法,表示是一个对象。
new关键字的作用:
- 1.创建空对象{}
- 2.this指向这个空对象 this={}
- 3.给对象赋值
- 4.返回这个对象 return this
通过这种方式创建的对象,会有一个属性constructor指向了CustomClass,如下所示:
console.log(c.constructor);
console.log(c.constructor === CustomClass);
输出:
ƒ CustomClass(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log(this.name, this.age);
}
}
true
这样,我们就可以通过constructor知道对象的类型。不过一般来说,都是通过instanceof操作符来判断对象的类型的。如下:
console.log(c instanceof CustomClass)
console.log(c instanceof Object)
输出:
true
true
可以看到,都是true,之所以Object也是true,那是因为所有的对象都继承自Object。
构造函数可以赋值给变量,然后通过变量来创建对象。
const CustomClass = function(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log(this.name, this.age);
}
}
let c = new CustomClass('xxx', 11);
c.say();
调用构造函数的时候,参数可以不写,只要有new操作符,就可以调用构造函数创建对象。
let c = new CustomClass();
构造函数和普通函数没有区别,唯一的不同就是调用时候的不同。构造函数前面如果添加了new操作符,那么他就会创建出一个对象,否则,他就是一个普通的函数。
通过构造函数创建的对象,会有一个问题,就是对象的方法每次创建对象时,都是新建一个方法,然后赋值给对象。这样就会导致不同的对象,相同的方法不是同一个对象。如下所示:
let c1 = new CustomClass();
let c2 = new CustomClass();
console.log(c1.say === c2.say)
输出:
false
这是可以解决的,我们只需要让函数只创建一次就可以了,如下所示:
function CustomClass(name, age) {
this.name = name;
this.age = age;
this.say = say
}
function say() {
console.log(this.name, this.age);
}
在外部创建,然后内部引用同一个函数,可以解决上述问题。但是这样非常容易造成需要在外部定义多个函数,导致代码可能会被分散在各个地方。
3.原型模式创建
每一个函数,都有一个prototype属性,我们叫做原型。我们可以通过prototype属性,将需要在构造函数内赋值的值,在外部赋值给prototype属性,这样,创建出来的对象实例就都会通过原型获得这些值。
function Person() {}
Person.prototype.name = "哈哈哈";
Person.prototype.age = 29;
Person.prototype.sayName = function() {
console.log(this.name);
};
let person1 = new Person();
person1.sayName(); // "哈哈哈"
let person2 = new Person();
person2.sayName(); // "哈哈哈"
console.log(person1.sayName == person2.sayName); // true
我们需要了解到,无论何时,只要创建出一个函数,就会给该函数创建出一个prototype属性,指向了原型对象。默认情况下,所有的原型对象会自动获得一个constructor属性,指向与之关联的构造函数。
然后在调用属性或者方法的时候,会先在对象实例本身进行搜索,如果实例上有该方法属性,则执行,没有则会沿着prototype找到原型对象,如果原型对象上有,则执行。
in操作符可以判断属性是否可用。该属性在实例或者原型上,都会返回true。
hasOwnProperty方法,如果属性在原型上,则会返回true。
4.通过类创建
使用关键字class声明类,然后创建出对象。
// 类声明
class Person {}
// 类表达式
const Animal = class {}
可使用constructor关键字,在类定义内部创建类的构造函数,constructor会告诉解释器,在使用new操作符创建新实例时,调用该函数。如下:
class Person {
constructor() {
console.log('init')
}
}
let p = new Person() // init
可在实例创建时,传入参数,也可以不传,不传参数时,创建的时候类后面的()也可以省略。如下:
class Person {
constructor(name) {
this.name = name
console.log('init', name)
}
}
let p = new Person() // init undefined
let p2 = new Person("aa") // init aa
let p3 = new Person // init undefined
类构造和构造函数构造主要区别是,类构造必须使用new操作符,构造函数的话,不写new操作符,那就是一个普通的函数,类构造不写则会报错。
网友评论