zoukankan      html  css  js  c++  java
  • javascript继承机制 & call apply使用说明

    一、继承机制

    1、对象冒充:构造函数使用 this 关键字给所有属性和方法赋值,可使 ClassA 构造函数成为 ClassB 的方法,然后调用它。

    function ClassZ() {
        this.newMethod = ClassX;
        this.newMethod();
        delete this.newMethod;
    
        this.newMethod = ClassY;
        this.newMethod();
        delete this.newMethod;
    }

    这里存在一个弊端,如果存在两个类 ClassX 和 ClassY 具有同名的属性或方法,ClassY 具有高优先级。因为它从后面的类继承。除这点小问题之外,用对象冒充实现多重继承机制轻而易举。

    2、apply()、 call() 方法是与经典的对象冒充方法最相似

    function ClassB(sColor, sName) {
        //this.newMethod = ClassA;
        //this.newMethod(color);
        //delete this.newMethod;
        ClassA.call(this, sColor);
    
        this.name = sName;
        this.sayName = function () {
            alert(this.name);
        };
    }

    3、原型链

    function ClassA() { } 
    ClassA.prototype.color = "blue"; 
    ClassA.prototype.sayColor = function () {     
        alert(this.color); 
    }; 
    function ClassB() { } 
    ClassB.prototype = new ClassA();

    把 ClassB 的 prototype 属性设置成 ClassA 的实例
    注意:调用 ClassA 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
    二、call & apply
    apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性.Function.apply(obj,args)方法能接收两个参数  
    call:和apply的意思一样,只不过是参数列表不一样.  Function.call(obj,[param1[,param2[,…[,paramN]]]])  
    对象的继承,一般的做法是复制:Object.extend
    Object.extend = function(destination, source) { 
        for (property in source) { 
            destination[property] = source[property]; 
        } 
        return destination; 
    }

    除此之外,还有种方法,就是:Function.apply或者Function.call。 通过 call() 或 apply() 方法可以设置 this 的值, 且作为已存在对象的新方法调用。

    在 JavaScript 严格模式(strict mode)下, 在调用函数时第一个参数会成为 this 的值, 即使该参数不是一个对象。
    在 JavaScript 非严格模式(non-strict mode)下, 如果第一个参数的值是 null 或 undefined, 它将使用全局对象替代。

    使用场景:

    1、 arguments 转换为数组

    // 返回的是数组,但是arguments本身保持不变
    vararg=[].slice.call(arguments);
    //[].slice.call(document.getElementsByTagName('li')); 

    2、借用

    var foo = { 
        name: 'joker',
        showName: function() { 
            console.log(this.name); 
        } 
    } 
    var bar = { 
        name: 'rose' 
    } 
    foo.showName.call(bar);    

    3、继承

    var Student = function(name, age, high) {
         // use call
         Person.call(this,name,age);
         this.high=high;
    }

    Person.apply(this,arguments);  

    this:在创建对象在这个时候代表的是student  

    arguments:是一个数组,也就是[“qian”,”21”,”一年级”];  

    用student去执行Person这个类里面的内容,在Person这个类里面存在this.name等之类的语句,这样就将属性创建到了student对象里面 

    在给对象参数的情况下,如果参数的形式是数组的时候,比如apply示例里面传递了参数arguments,这个参数是数组类型,并且在调用Person的时候参数的列表是对应一致的(也就是Person和Student的参数列表前两位是一致的) 就可以采用 apply , 如果我的Person的参数列表是这样的(age,name),而Student的参数列表是(name,age,grade),这样就可以用call来实现了,也就是直接指定参数列表对应值的位置(Person.call(this,age,name,grade));

    4、 封装对象时保证this的指向

    var _this = this; 
    _this.$box.on('mousedown', function() { 
        return _this.fndown.call(_this); 
    })

    5、代码优化

    返回数组最大值

    alert(Math.max(5,8))   //8
    alert(Math.max(5,7,9,3,1,6))   //9
    alert(Math.max([5,7,9,1]))    // 找出数组中最大的元素,这样却是不行的。
    
    function getMax(arr){
        var arrLen=arr.length;
        for(var i=0,ret=arr[0];i<arrLen;i++){
            ret=Math.max(ret,arr[i]);
        }
        return ret;
    }
    
    //这样写麻烦而且低效。如果用 apply呢
    function getMax2(arr){
        return Math.max.apply(null,arr);
    }

    两段代码达到了同样的目的,但是getMax2却优雅,高效,简洁得多。
    apply会将一个数组装换为一个参数接一个参数的传递给方法。这块在调用的时候第一个参数给了一个null,这个是因为没有对象去调用这个方法,我只需要用这个方法帮我运算,得到返回的结果就行,.所以直接传递了一个null过去 。 
    //两个数组拼接,要把 arr2展开,然后一个一个追加到arr1中去
    var arr1=[1,3,4];
    var arr2=[3,4,5];
    arr1.push(arr2)//[1,3,4,[3,4,5]]显然不行
    //只能用一个循环去一个一个的push(当然也可以用arr1.concat(arr2),但是concat方法并不改变arr1本身)
    var arrLen=arr2.length
    for(var i=0;i<arrLen;i++){
        arr1.push(arr2[i]);
    }
    //使用apply,arr1执行push方法,arr2作为参数传入。arr1调用了push方法,参数是通过apply将数组装换为参数列表的集合
    Array.prototype.push.apply(arr1,arr2)

     
    call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。因为 JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。二者的作用完全一样,只是接受参数的方式不太一样 
    function add(a, b){console.dir(this);}
    function sub(a, b){console.dir(this);}
    add(1,2); //"Window"
    sub(1,2); //"Window"
    add.call(sub, 1, 2); //"sub(a, b)"
    sub.apply(add, [1, 2]); //"add(a, b)"
  • 相关阅读:
    Android实现多个词汇连续输入的提示
    android 中使用AutoCompleteTextView 可以实现自动提示功能
    关于android中搜索功能的实现
    重复弹出Toast 解决方案
    Android显示不重复通知的Notification
    个人项目经历
    使用Google 官方的控件SwipeRefreshLayout实现下拉刷新功能
    安卓左滑实现返回上一个页面
    初学hadoop
    浅谈nodejs和php
  • 原文地址:https://www.cnblogs.com/chenlogin/p/5140705.html
Copyright © 2011-2022 走看看