工厂模式
- 单例模式虽然解决了分组的作用,但不能实现批量的生产
- 工厂模式把实现同一间事情的相同代码放到一个函数中,以后如果再想实现这个功能,不需要重新编写这些代码,只需要执行当前的函数即可,也叫–>“函数的封装”
-减少页面中的冗余代码,提高代码的重复利用率–>低耦合高内聚
-面向对象:函数的封装,继承(子类继承父类的方法和属性等,祖传),多态:包括重载和重写,js中只有重写,但是却可以模拟重载.
- js中有一个操作类似重载但不是重载的,我们可以根据传递参数的不同,实现不同的功能
function sun(num){
if (typeof num ==="undefined"){
return 0;
}
return num;
}
sum(100);
sum();
构造函数模式和工厂模式的区别:
-普通函数执行:createJsPerson()
-构造函数模式:new CreateJsPerson() 通过new执行后,我们的CreateJsPerson就是一个类了,而函数执行的返回值(p1)就是CreateJsPerson这个类的一个实例–>JS中所有的类都是函数数据类型的,通过new执行变成了一个类,但是它本身是一个普通的函数 ->JS中所有实例都是对象数据类型的
-相同点:都是形成一个私有的作用域,然后 形参赋值->预解释->代码重上到下执行
-不同点:
->在代码执行之前,不同自己手动创建一个obj对象,浏览器会默认返回一个对象类型的值(这个对象其实就是我们当前类的一个实例)
->接下来代码开始从上到下执行,以当前的实例为执行的主体(this代表的就是当前的实例),然后分别把属性名和属性值赋值给当前的实例
->最后浏览器会默认把创建的实例返回
–>JS中所有的类都是函数数据类型的,通过new执行变成了一个类,但是它本身是一个普通的函数
->JS中所有实例都是对象数据类型的
->p1和p2都是CreateJsPerson这个类的实例,所以都拥有writeJs这个方法,但是不同实例之间的方法是不一样的。在类中给的实例增加的属性(this.xxx = xxx)属于当前实例的私有的实行,实例和实例之间是单独的个体,所以私有的属性之间是不相等的
//console.log(p1.writeJs === p2.writeJs)//false
function Fn(){
var num = 10;// window
this.x = 100;//->f1.x = 100
this.getX=function(){
console.log(this.x);
}
}
var f1 = new Fn;
consloe.log(f1.num);//undefined
- this的问题:在类中出现的this.xxx=xxx中的this都是当前类的实例,而某一个属性值(方法),方法中的this需要看方法执行的时候,前面是否有“ . ”才能知道this是谁
- 类有普通函数的一面,当函数执行的时候,var num其实只是当前形式的私有作用域中的私有变量而已,它和我们的f1这个实例没有任何关系,只有this.xxx=xxx才相当于给f1这个实例增加私有的属性值
原型模式
- 每一个函数数据类型(普通函数、类)都有一个天生自带的属性:prototype(原型),并且这个属性是一个对象数据类型的值,所以会默认开一个堆内存!
- 并且在prototype上浏览器天生给它加了一个属性constructor(构造函数),属性值是当前函数(类)的本身
- 每一个对象数据类型(普通的对象、数组、正则、 实例、prototype …)也天生自带一个属性:proto,属性值是当前实例所属类的原型(prototype)
function Fn(){
this.x = 10;
}
Fn.prototype.getX = funtion(){
console.log(this.x);
}
var f1=new Fn;
var f2=new Fn;
console.log(Fn.prototype.constructor === Fn); //true
- 不管f1 instanceof Object ->true 因为f1通过proto可以向上级查找,不管有多少级,最后总能找到Object
- 在Object原型上没有proto这个属性(因为Object是最顶层)
原型链模型
f1.hasOwnProperty("x");//hasOwnProperty是f1的一个属性
然而f1的私有属性上并没有这个方法,因此
- 通过对象名.属性名 的方式获取是性质的时候,首先在对象的私有属性上进行查找,如果有这个属性,则获取的是私有的属性值;
- 如果私有的没有,则通过proto找到所属类的原型(类的原型上定义的属性和方法都是当前实例公有的属性和方法,原型上存在的话,获取的是公有的属性值)。如果原型上也没有,则继续通过原型的_proto_继续向上查找,一直找到Object.prototype为止
解题步骤:
function Fn(){
this.x = 10;
this.y = 20;
this.getY = function(){
console.log(this.y);
}
}
Fn.prototype = {
constructor: Fn,//要指向Fn这个函数,不然会指向到原型(object)中
y:30;,
getX : function(){
console.log(this.x);
},
getY : function(){
console.log(this.y);
}
};
var f = new Fn;
f.getX(); //->console.log(f.x)->10;
f.__proto__.getX(); //->this是f.__proto__.->console.log(f.__proto__.x)->undefined
Fn.prototype.getX() //undefined
f.getY() // console.log(f.y)->20;
f.__proto__.getY();//30
在原型模式中,this常用的两种情况:
- 在类中this.xxx=xxx; this->当前类的实例
- 某一个方法中的this -> 看执行的时候” . “前面的是谁this就是谁
思路步骤
- 需要先确定this的指向(this是谁)
- 把this替换成对应的代码
- 按照原型链查找的机制,一步步的查找结果
在内置类的原型上扩展我们的方法
数组去重
Array.prototype.myUnique = function(){
var obj = {};
for(var i=0;i<this.length;i++){
var cur = this[i];//获得当前项
if(obj[cur]==cur){//判断是否重复
this[i]=this[this.length-1];
this.length--;
i--;
continue;
}
obj[cur] = cur;
}
obj = null;
};
var ary = [12,14,11,23,23,12,43,11] ;
ary.myUnique();
console.log(ary);
链式写法:执行完成数组的一个方法可以紧接着执行下一个方法
- 原理:ary为什么可以使用sort方法?因为sort是Array.prototype上的公有的方法,而数组ary是Array这个类的一个实例,所以ary可以使用sort方法->数组才能使用我们Array原型上定义的属性和方法
sort执行完成的返回值是一个排序后的“数组”,而pop执行完成后返回的是删除的元素,不是一个数组,所以不能再pop后面再添加
var ary = [12,15,22,21,12,15,22]
ary.sort(function (a, b){
return a - b;
}).revarse().pop();
批量设置公有属性
- 只有浏览器天生给Fn.prototype开辟的堆内存里面有constructior,而我们自己开辟的这个堆内存没有这个属性,这样constructor指向就不是Fn,而是Object。
-因此为了保持和原来的一致,我们需要手动增加constructior指向
- 重构原型对象的方式->自己开辟一个堆内存,存储我们公有的属性和方法,把浏览器原来的Fn.prototype开辟的那个替换掉
function Fn(){
this.x = 10;
}
Fn.prototype = {
constructor = Fn,
a : function (){
},
b : function (){
}
};
var f = new Fn;
原型链模式的继承方式
- 原型继承: 是我们JS中最常用的一种继承方式,->子类B想要继承父类A中的所有的属性和方法(私有的和公有的),只需让B.prototype = new A;就可以
-注意:它是把父类中私有的+共有的都继承到了子类的原型上(子类公有的)
-核心:原型继承并不是把父类中的属性和方法克隆一模一样的给B,而是让B和A之间增加了原型链的连接,以后B的实例n想要A 中的getX方法,需要一级级的向上查找来使用
function A(){
this.X = 10;
}
A.prototype.getX = function(){
console.log(this.x);
};
function B(){
this.x = 20;
}
B.prototype = new A;