构造函数模式
this 调用函数对象的本身
什么是构造函数?
构造函数前用new,调用的方式与普通函数不同。但是本质上就是函数。构造函数与普通函数是强行分别出来的。
任何函数只要是有new操作的,则一定为构造函数。否则与其他函数无区别
构造函数与工厂模式的区别
- 无显示的创建对象
- 属性和方法直接赋值给this
- 无return语句
- 构造函数名大写
如果直接运行构造函数呢?
构造只是可以创建对象。
如果无new则是全局运行(window)
new后方法地址不同:
xiaohong.sayName!=xiaozhang.sayName
非引用类型则是开辟新的位置。
实例._proto_=Array.prototype
argument
返回数组,加了… 则是参数的逆运算,将一个数组转化为逗号分隔的参数序列
30 模式
30.1 组合模式
//需要独一无二 开辟自己空间则用构造函数模式
function Person(name,age){
this.age=age;
this.friend=['mary','tom'];
}
//追求可复用
Person.prototypoe.name="chen";
Person.prototype.sayName=function(){
console.log(this.name);
}
let zhang =new Person("zhang",10);
组合模式是目前最广泛的自定义类型的方法
30.2 动态原型
将所有方法放到构造函数内部(做判断
function Person(name,age){
this.age=age;
this.friend=['mary','tom'];
}
if(typeof this.name !=="function"){ //此开关可以是任意的
Person.prototype.sayName=fucntion(){ //下一次才会有实例方法
console.log(this.name);
}
}
此原型可以检测网络状态
不能用对象的字面量重写原型,会切断实例与原型的联系(无constructor
30.3 寄生构造
像工厂模式,唯一不同的是需要new操作符
function Person(name,age){
//寄生意味先在此 let o1=new Person(); 如果此行有,则下一行
let o=new Object();
o.name=name;
o.age=age;
o.friend=['mary','tom'];
o.sayName=function(){
console.log(this.name);
};
//return o; //+加了这个则为寄生。Object实例
//return o1; //不返回值 默认返回新对象实例-Person实例
}
let zhang=Person("zhang",10); //工厂模式,Object创建,要加return o
let yin=new Person("yin",20); //构造模式
寄生则意味着“截胡”——在构造函数里寄生工厂,要调用则加return o(则可以截胡到,就会调用工厂模式。
寄生的使用
对于顶级对象的方法修改:
function addArray (type,name,age){
let a;
switch (type){
case "Array":
a=new Array();
break;
case "Object":
a=new Object();
break;
}
a.name=name;
a.age=age;
a.sayName=fucntion(){
log(this.name)
}
return a; //若删除后只为普通构造函数
}
(最后闯出来的构造函数对象是其他的)=> 寄生
例如Array,Object等
30.4 严格模式
大型企业项目为了安全起见
1.用的非常少
2.eval() 将字符串当做是函数立马执行
传入的不变 保持最开始的形式
1.无new
2.不用this
构造函数与构造函数见instanceof 检测不出(只能检测构造与实例
先执行函数参数,再执行函数体,ES6在参数里使用,则不能在里面用严格模式。
30.5 原型继承
31 继承
31.1 经典继承
1.call方法(伪造对象
使用方法:
fn.call({对象},参数1,参数2...)
fn为函数:对象调用fn,this指向调用的对象。
Signal.prototype.ch.call("tom",188) //相当于tom.Signal.prototype.ch(188)
手写call方法:
Function.prototype.call2 = function (thisArg) {
//先判断是不是空的,是的话指向window,不是的话采用Object方法,将thisArg传进去,返回那个对象
thisArg = thisArg == null ? window : Object(thisArg);
// log( Object(thisArg)); Object方法,将thisArg传进去,返回那个对象
// log(thisArg); //调用的对象
log(this); //全程指向那个方法fn
//然后将剩下的使用[...rest]将它变为数组,然后返回一个新对象(slice复制
let args = [...arguments].slice(1);
// log(args)//新参数
let symbolFn = Symbol('fn');
thisArg[symbolFn] = this; //方法 调用对象.方法
let res = thisArg[symbolFn](...args);//调用对象.方法(参数)
delete thisArg[symbolFn];
return res;
}
2.apply方法
使用方法:
fn.call({对象},[参数1,参数2...])
//fn.call({},[...a,...b]);
与call一样,仅仅是多了“ [ ] ”
使用场景:用数组参数使用。
3.bind方法
使用方法:
fn.bind({对象},参数1,参数2...)
返回对象数组本身(重新创建新函数,可以先固定死函数
总结:
1.子类型构造函数里用超类构造函数。
2.是借用,并不是完整继承,但是拥有超类的函数方法
例子:
function yeye(){
this.colors=['green','red'];
}
function Baba(){
yeye.call(this) //函数在运行而已(o.yeye()
}
let o=new Baba();
o instanceof Baba //true
o instanceof yeye //false
↑仅仅是调用函数而已(伪继承
优点:原型链更简单、可以传参数(父向子传
31.2 组合继承
function SuperType(name){
this.name=name;
this.colors=['red','green'];
}
SuperType.prototype.sayName=function(){
log(this.name);
}
function SubType(name,age){
//继承属性!
SuperType.call(this.name);
this.age=age;
}
//继承方法
SubType.prototype=new SuperType(); //一个对象的实例可以作为另一个对象的原型
SubType.prototype.constructor=SubType;
SubType.prototype.sayAge=funtion (){
log(this.age);
}
var instance1=new SubType("wan",18);
总结:
1.都无SuperType,仅在SubType中设SuperType.call(this.参数)
2.需动手定义constructor
3.缺点:需调用两次构造函数
31.3 原型式继承
function object(o){
funtion F(){}
F.prototype=o;
return new F();
}
var person={
name:'wan',
friends:['tom','jerry']
};
var b=object(person);
b.name="gray";
总结:
借助原型可以给予已有的对象创建对象,不必自定义类型
31.4 寄生式继承
和组合继承类似
31.5 寄生组合继承
function SuperType(name){
this.name=name;
this.colors=['red','green'];
}
SuperType.prototype.sayName=function(){
log(this.name);
}
function SubType(name,age){
//继承属性!
SuperType.call(this.name);
this.age=age;
}
function object(o){
funtion F(){}
F.prototype=o;
return new F();
}
function inhertPrototype(SubType,SuperType){
var prototype=object(SuperType.prototype);
prototype.constructor=SubType; //↑对
SubType.prototype=prototype; //指定对象
}