对象创建的6种方式
1、工厂模式
使用函数来封装对象的细节,缺点是封装出来的对象无法与某个类型联系起来
//工厂模式
function func1(name, age, family) {
let obj = new Object();
obj.name = name;
obj.age = age;
obj.family = family;
obj.say = function () {
console.log(this)
}
return obj
}
const obj = func1('lisi', 18, { name: 'zhangsan'});
/*
{
name: 'lisi',
age: 18,
family: {
name: 'zhangsan'
},
say: function () {
console.log(this)
}
}
*/
obj.say(); // 指向obj
2、构造函数模式
new一个构造函数的时候会创建一个对象,对象的原型链指向构造函数的原型,然后将执行上下文的this指向这个对象,优点是创建的对象与构造函数产生了联系。但是造成了不必要的函数对象创建,函数也是一个对象。
fucntion func2(name, age, family) {
this.name = name;
this.age = age;
this.family = family;
this.say = function () {
console.log(this)
}
}
const obj = new func2('lisi', 18, { name: 'zhangsan' })
3、原型模式,每一个函数都有一个prototype属性,这个属性是一个对象,包含了通过构造函数创建的所有实例都能共享的属性和方法。因此可以使用原型添加公共属性和方法从而实现代码的复用。
function func3() {}
func3.prototype.name = 'lisi';
func3.prototype.age = 18;
func3.prototype.family = { name: 'lisi' };
const obj1 = new func3();
const obj2 = new func3(.)
4、组合模式,结合构造函数模式和原型模式,也叫做混合模式,
function Mixin(name, age, family) {
this.name = name;
this.age = age;
this.family = family;
}
Mixin.prototype = {
constructor: Mixin,
say: function () {
console.log(this)
}
}
const obj1 = new Mixin('lisi', 18, { name: 'zhangsan' });
const obj2 = mew Mixin('wangwu', 19, { name: 'wangergou' });
5、动态原型模式,这一种模式是将原型方法的赋值移动到了函数的内部,通过对属性是否存在的判断可以实现仅在第一次调用函数的时候对原型对象赋值一次的效果,相当于对混合模式的封装
function MixinNew(name, age, family) {
this.name = name;
this.age = age;
this.family = family;
if (MixinNew.prototype.say !== 'function') {
Mixin.prototype.say = function () {
console.log(this)
}
}
}
const obj = new MixinNew('lisi', 18, { name: 'zhangsan'})
6、寄生构造函数模式。和工厂函数的实现方式基本相同,基于一个已经有的类型,在实例化的时候对实例化的对象进行扩展;
function Person(age, name) {
const obj = new Object();
obj.name = name;
obj.age = age;
obj.say = function () {
console.log(this)
}
return obj;
}
应用实例
function Person() {
let newArr = new Array();
newArr.push.apply(newArr, arguments);
newArr.toPipedString = function () {
return this.Join('|')
}
newArr.length = [...arguments].length;
return newArr
}
const obj = new Person('lisi', 'zhangsan', 'wangwu')
console.log(obj);
for (let value of obj) {
console.log(value);
}
7、稳妥构造函数模式,只能通过say函数访问自己的变量
function func(name) {
const obj = new Object();
obj.name = name;
obj.say = function () {
console.log(this.name)
}
return obj;
}
对象的继承方式
1、原型链继承,将父类的实例作为子类的原型,缺点是父类新增原型方法和原型属性子类都能访问到,父类一变他也变了。
function Parent(name) {
this.name = name;
}
Parent.prototype.getName = function () {
return this.name
}
function Children(age) {
this.age = age;
}
Children.prototype = new Children(18)
2、构造函数继承,通过子类型的函数中调用父类型的构造函数来实现的。解决了无法向父类型传递参数的问题,存在的唯一的问题就是无法实现函数方法的复用;
function Parent(name) {
this.name = name;
this.friends = ['lisi', 'zhangsan']
}
function Children(age) {
Parent.call(this, 'xiaohong');
this.age = age;
}
const obj = new Children(19)
3、组合式继承,通过调用父类型的构造函数,继承父类型的属性并且保留传参的优点,然后通过父类实例作为子类的原型,实现函数的复用。缺点是调用了两次父类型的实例生成了两份实例。
function Parent(name) {
this.name = name;
}
Parent.prototype.getName = function () {
return this.name;
}
function Children(age) {
this.age = age;
Parent.call(this, 'lisi');
}
Children.prototype = new Parent('zhangsan');
const obj = new Children(18)
5、寄生组合式继承,通过寄生的方式砍掉了父类型的实例,避免了组合式继承的缺点。
function Parent(name) {
this.name = name;
this.friends = ['lisi', 'zhangsan']
}
Parent.prototype.getName = function () {
return this.name;
}
function Children(age) {
this.age = age;
Parent('lisi');
}
(function () {
var Super = function () {};
Super.prototype = Parent.prototype;
Parent.prototype = new Super()
})
const obj = new Children(19)
\