日常笔记

call和apply

call和apply的作用就是改变this的指向,区别就是传参列表不同

call和apply可以理解为用别人的函数实现自己的需求,call必须符合调用的函数的形参,不可删除形参

function a(){
}
a.call() = a()

call和apply更多用于组装函数 由我来组成头部

call是把实参按照形参的个数传入,apply则是需要传入一个数组arguments

call是按照形参个数传实参

function Wheel(Wheelsize,style){
    this.wheelsize = Wheelsize;
    this.style = style
}
function Sit(sitColor){
    this.sitColor = sitColor;
}
function Model(width,height,len){
    this.width = width;
    this.height = height;
    this.len = len;
}

function Car(Wheelsize,style,sitColor,width,height,len){
    Wheel.call(this,Wheelsize,style);
    Sit.call(this,sitColor);
    Model.call(this,width,height,len);
}

var BMW = new Car(100,"幻夜",black,100,100,100);

apply则是需要传入一个数组arguments

function Wheel(Wheelsize,style){
    this.wheelsize = Wheelsize;
    this.style = style
}
function Sit(sitColor){
    this.sitColor = sitColor;
}
function Model(width,height,len){
    this.width = width;
    this.height = height;
    this.len = len;
}

function Car(Wheelsize,style,sitColor,width,height,len){
    Wheel.call(this,[Wheelsize,style]);
    Sit.call(this,[sitColor]);
    Model.call(this,[width,height,len]);
}

var BMW = new Car(100,"幻夜",black,100,100,100);

bind

bindcall还有apply都是去重新定义this这个对象的。

const name = "小钟",age = 20;
let obj = {
    name:"小周",
    objAge:this.age,
    myFun:function(){
        console.log(this.name+"年龄"+this.age);
    }
}
const db = {
    name:"旭宇",
    age:"99"
}
obj.myFun.call(db);         //旭宇年龄99
obj.myFun.apply(db);        //旭宇年龄99
obj.myFun.bind(db)();       //旭宇年龄99

由上面例子可以看出来,除了调用bind方法后面多了一个()外,结果返回跟apply和call都一致!

由此得出结论,bind返回的是一个新的函数,必须得调用才会执行

bind()最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值。常见的错误就像上面的例子一样,将方法从对象中拿出来,然后调用,并且希望this指向原来的对象。如果不做特殊处理,一般会丢失原来的对象。使用bind()方法能够很漂亮的解决这个问题:

this.num = 9; 
var mymodule = {
  num: 81,
  getNum: function() { return this.num; }
};
module.getNum(); // 81
var getNum = module.getNum;
getNum(); // 9, 因为在这个例子中,"this"指向全局对象
// 创建一个'this'绑定到module的函数
var boundGetNum = getNum.bind(module);
boundGetNum(); // 81

继承模式

公有原型

最基础的继承是这样的,同一个原型被两个函数指向

function Son(){
}
function Father(){
}
Son.prototype = Father.prototype;
var son = new Son;
var father = new Father;

模块化封装起来起来就是:

function Son(){
}
function Father(){ 
}
function inherit(Target, Origin){    
    Target.prototype = Origin.prototype;
}
inherit(Son, Father);
var son = new Son;
var father = new Father;

但这个有个不足就是,无法给单个被继承的函数的原型添加属性(因为指向同一个原型,一加属性就一起加)

最终模式——圣杯模式

思路是:建立一个function F()作为中间层,利用原型链的原理

function Son(){
}
function Father(){ 
}
function inherit(Target, Origin){    
    function F(){}
    F.prototype = Origin.prototype;
    Target.prototype = new F(); //把Target函数的原型换成F,但是通过原型链的原理,Target函数的原型最终还是继承于Origin函数的原型,就可以解决公有原型继承的缺点。
    Target.prototype.constructor = Target; //构造函数归位
    Target.prototype.uber = Origin.prototype //声明超类(超级父级,究竟继承至谁)
    //正常超类是写super,但是js里super是保留字,所以这里写uber
}
inherit(Son, Father);
var son = new Son();
var father = new Father();