对象的继承和方法

继承

对象之间的继承

var wjl = {
name:'王健',
money:100000,
car:['宝马','玛莎拉蒂'],
play:function(){
console.log('abc');
}
}
var wsc = {
name:'王思';
}
继承函数
function extend(parent,child){
for(var key in parent)//遍历parent的所有属性
if(child[key])//如果child中有这个属性名就跳过这次循环,直接下一次循环{
continue;//continue是跳过此次循环,直接执行下一次循环.
}
child[key]=parent[key]//把parent对象中的属性都遍历给child对象
}
}
extend('wjl','wsc');

 

原型之间的继承

 继承的目的 是把子类型中共同的成员提取到父类型中,代码重用

(定时器中的this指向的是window对象),可以通过创建一个变量的方式来访问自调用函数内的对象。例如。设置that=this;

 

 

组合继承

借用构造函数+原型继承

window.onload=function(){
 function Person(name,age,sex){
     this.name=name;
     this.age=age;
     this.sex=sex;
 }//父对象
 Person.prototype.sayhi=function(){
     console.log(123);
 }
 function Student(name,age,sex,score){
     Person.call(this,name,age,sex);
     this.score=score;
 }//子对象
 Student.prototype=new Person;//还有种写法是 Student.prototype=Person.prototype; 但是这种写法有个问题
Student.prototype在内存中不是独立的空间,而且指向了person的原型空间,这样的话 student添加自己的方法,就等于person添加方法
 Student.prototype.constructor=Student;
 var s1=new Student('lilei',18,'man',90);
 console.dir(s1);//继承了父对象的属性和原型方法
}


例子的原型图
 

 

寄生继承

function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function () {
    console.log(this.name)
}

function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
    // 通过构造一个介于 Parent 与 Child 之间的对象,并使该对象的 prototype 属性指向 Parent 的 prototype对象,
    // 来避开通过调用 Parent 构造函数的方式来产生一个 prototype 指向Parent prototype对象的对象。
}

function prototype(child, parent) {
// 不直接child.prototype=parent.prototype呢?
// 原因 : 当我们想给 Child 的prototype里面添加共享属性或者方法时,如果其 prototype 指向的是 Parent 的 prototype,那么在 Child 的 prototype 里添加的属性和方法也会反映在 Parent 的 prototype 里面,
// 这明显是不合理的,这样做的后果是当我们只想使用 Parent 时,也能看见 Child 往里面扔的方法和属性。
// 所以需要每个构造函数都需要持有自己专用的prototype对象
    var prototype = object(parent.prototype);
    prototype.constructor = child;
    child.prototype = prototype;
}

prototype(Child, Parent);

var child1 = new Child('kevin', '18');

console.log(child1);

 bind()方法

 bind方法 ES5中新增 IE9才支持,新建一个方法,bind中的第一个参数可以改变函数中的this指向,例如,f.bind(obj),实际上可以理解为obj.f(),这时,f函数体内的this自然指向的是obj.     bind并不会调用函数,而且在内存中重新创建了一个函数,并且函数内this指向第一参数 

例子

 

再看另外一种用法

例子

function f(y, z){
return this.x + y + z;
}
var m = f.bind({x : 1}, 2);
console.log(m(3));
//6

注意:这里bind方法会把它的第一个实参绑定给f函数体内的this,所以这里的this即指向{x : 1}对象,从第二个参数起,会依次传递给原始函数,这里的第二个参数2,即是f函数的y参数,最后调用m(3)的时候,这里的3便是最后一个参数z了,所以执行结果为1 + 2 + 3 = 6
分步处理参数的过程其实是一个典型的函数柯里化的过程(Curry)

(浅谈函数柯里化)

curry 的概念:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数

先看一个简单例子,add函数接受 2 个参数(或者多个),addX函数接受 1 个参数。
换而言之,所谓"柯里化",就是把一个多参数的函数,转化为单参数函数。将一个函数转换为一个新的函数

// 非柯里化
function add(x, y) {
    return x + y;
}

add(1, 2) === 3; // true

// 柯里化
function addX(y) {
    return function(x) {
        return x + y;
    };
}

addX(2)(1) == 3; // true

 

柯里化好处:

  • 代码复用,减少维护成本
  • 尽可能的函数化,便于阅读

 

call()方法

改变函数中的this,直接调用函数

比如 fn.call(O) 直接调用fn函数 并且this指向o

call的返回值就是函数的返回值

 

 call()例子

 //[object object]  5,9  [object Array]  最后例子是用object原型对象里面的toString来判断数据类型,把tihs指向了arr ,[object Array]指的是前面代表的对象,后面是对象类型

 

借用构造函数

 function Person(name,age,sex){
     this.name=name;
     this.age=age;
     this.sex=sex;
 }
 function Student(name,age,sex,score){
     Person.call(this,name,age,sex);//第一个this是指向的Student函数,把student函数传给了person。而后面三个是传的参数
//只借用属性里面的,不借用原型里面的 this.score=score; } var s1=new Student('lilei',18,'man',90); console.dir(s1);

 

javascript中call()、apply()、bind()的用法终于理解

 

先看明白下面:

  例1

  obj.objAge;  //undefined

  obj.myFun()  //小张年龄undefined

  例2
 

 shows()  // undefined

 

比较一下这两者this 的差别,第一个打印里面的this 指向obj,第二个全局声明的shows()函数   this 是window ;

 

1,call()、apply()、bind() 都是用来重定义 this 这个对象的!

  如:

  

  obj.myFun.call(db);    //德玛年龄99

    obj.myFun.apply(db);    //德玛年龄99

    obj.myFun.bind(db)();   //德玛年龄99

  以上出了bind 方法后面多了个 () 外 ,结果返回都一致!
  由此得出结论,bind 返回的是一个新的函数,你必须调用它才会被执行,call和apply都是直接调用
 
  2,对比call 、bind 、 apply 传参情况下
  
  

  obj.myFun.call(db,'成都','上海');     //德玛 年龄 99  来自 成都去往上海

  obj.myFun.apply(db,['成都','上海']);        //德玛 年龄 99  来自 成都去往上海  

  obj.myFun.bind(db,'成都','上海')();         //德玛 年龄 99  来自 成都去往上海

    obj.myFun.bind(db,['成都','上海'])();   //德玛 年龄 99  来自 成都,上海去往undefined

  

   微妙的差距!
  从上面四个结果不难看出
    call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,第二个参数差别就来了:
    call的参数是直接放进去的,第二第三第n个参数全都用逗号分隔,直接放到后面  obj.myFun.call(db,'成都', ... ,'string' );
    apply的所有参数都必须放在一个数组里面传进去  obj.myFun.apply(db,['成都', ..., 'string' ]);//apply常见应用就是把数组展开传给函数
    bind除了返回是函数以外,它 的参数和call 一样。
    当然,三者的参数不限定是string类型,允许是各种类型,包括函数 、 object 等等!
     如果变量里有很多无关的值或者是指定为字面量,使用call方法则可以直接将其作为参数列表传递进入,如果这些变量已经在一个数组里面了,或者很容易收集到数组里,那么apply则是更好的选择
 

函数的其他成员

 

console.dir(fn)

 私有变量arguments不是fn.arguments。fn.arguments是一个属性、当函数的参数个数不固定时,在函数内部,可以通过argument获取到实际传过来的参数

 

 个人总结重点

 组合继承  借用构造函数加原型继承 比如Student.prototype=new Person Student会继承Person的属性和原型方法 

记得 设置了prototype后,要重新设置constructor

call() apply() bind()用法  首先都是用来重定义this这个对象的

但是bind返回的是一个新的函数,必须要调用才会执行

传参区别 三个函数的第一个参数都是this的指向对象,第二个参数差别  call是直接放进入,逗号隔开就行。bind也是。apply则是把参数放入一个数组传进去。apply常见应用就是把数组展开传给函数

posted @ 2020-06-12 18:52  Ren小白  阅读(294)  评论(0)    收藏  举报
levels of contents