导航菜单
  • 首页
  • 首页>前端万博manbext备用网址>JavaScript万博manbext备用网址

    函数作为对象的属性和方法(call、apply、bind)

    我不会java,但是看过一些文章,说的是java里面的函数必须有一个对象带着才能使用,比如obj.fn(),但是在JavaScript中,函数作为一个独立的个体,不需要obj对象作为大哥带着小弟玩儿了,因为函数在JavaScript中,本身就是对象,所以把函数也叫做一等公民。函数可以单独使用,也可以在对象下面被调用,还可以当作值传递,反正掌握了函数,JavaScript就算会了一半儿。

    1、函数作为对象

    函数也是对象,也有作为对象的特性,拥有自己的属性和方法。

    1.1 属性

    1.1.1 length属性

    函数的length属性表示形参的个数。函数内部有一个arguments对象,arguments对象的length属性表示实参的个数。

    function foo(a,b){
        console.log(a + b);
        console.log(arguments.length); // 这个arguments只能在函数内部访问,在函数外部访问返回null。
    }
    console.dir(foo);//返回foo对象
    console.log(foo.arguments); // null
    console.log(foo.length);// 2

    1.1.2 name属性

    name属性很多浏览器早就支持了,但到ES6中才被纳入标准,该属性返回函数的名字。IE浏览器不支持,返回undefined。

    //函数声明
    function foo(){
        console.log(foo.name);
    }
    console.log(foo.name); // foo
    foo(); // foo
    
    //函数表达式
    let fn1 = function () {
        console.log(fn1.name); 
    }
    console.log(fn1.name); //fn1
    fn1(); // fn1
    
    //有名的函数表达式
    let fn2 = function timer(){
        console.log(fn2.name);
    }
    console.log(fn2.name);//timer
    fn2();//timer
    timer(); //ReferenceError: timer is not defined
    
    //匿名函数,返回空字符串。通过arguments.callee可以访问函数本身
    (function () {
        console.log(arguments.callee.name)
    })();

    1.2 方法

    1.2.1 apply()和call()

    apply()和call()这两个方法,它们的作用是一样的,都表示在特定的作用域中调用函数,它们都可以改变函数中this对象的值。

    函数声明在某一个作用域中,执行又可能在另一个作用域中,函数内部的this对象是在函数被调用的时候才能确定的,就表示当前调用函数的对象,也表示函数执行时的作用域范围。

    通过call()和apply()方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。

    let fn1;
    var name = 'window';
    function foo(a,b){
        let c = a + b;
        // 在函数内部声明的函数
        function fn(){
            // 访问了外层函数的变量c
            console.log(c);
            console.log(this.name);
        }
        // 把fn作为值传递给了外部变量fn1,构成了闭包。
        fn1 = fn;
    }
    foo(1,2); //先执行之后,fn1才有值。
    //执行获得的fn函数,闭包产生。
    fn1();  // 3 'window'
    
    // 创建一个对象
    let obj = {
        name:'obj'
    }
    // 把函数fn1的值fn函数内部的this指向obj对象。
    // 函数在哪里执行和在哪里声明没有关系。可以执行在一个作用域中,声明在另一个作用域中。因为函数是一个对象,可以被引用到任何地方执行。
    fn1.call(obj); // 3 'obj'
    fn1.apply(obj); // 3 'obj'
    
    //call()这种方法其实等价于
    obj.fn2 = fn1;
    obj.fn2();
    delete obj.fn2;
    //为对象扩充属性
    function car(color,name){
        this.color = color;
        this.name = name;
        console.log(this.color,this.name);
    }
    var obj1 = {
        id:1,
    };
    var obj2 = {
        id:2,
    };
    var obj3 = {
        id:3
    };
    // 扩充作用域的好处,就是方法和对象之间没有任何耦合关系。
    car.call(obj1,'red','奔驰');
    car.call(obj2,'black','宝马');
    car.apply(obj3,['white','大众']);
    console.log(obj1,obj2,obj3);
    
    //计算商品的总价
    let book1 = {
        name:'三国演义',
        count:125,
        price:'25元'
    }
    let book2 = {
        name:'隋唐英雄传',
        count:1250,
        price:'25元'
    }
    
    //统计书籍的价格,让方法和对象之间没有耦合关系。
    function getTotalPrice(){
        return (this.count * parseFloat(this.price)).toFixed(2);
    }
    console.log(getTotalPrice.call(book1));
    console.log(getTotalPrice.call(book2));

    apply()方法接收两个参数:第一个表示函数运行的作用域(即函数中this指向谁),也可以是arguments对象。;第二参数是一个数组,表示函数的参数。

    function toStr(){
        return Array.prototype.join.call(arguments,':');
    }
    console.log(toStr(1,2,3)); // 1:2:3

    call()方法和apply()方法类似,唯一区别就是参数的形式不一样,call()接收的是参数列表,apply()接收的是数组。

    //如果没有指定的对象,可以用null表示。
    let result = Math.max.apply(null,[10,25,3,45,20]);
    console.log(result)
    const oLis = document.querySelectorAll('li');
    //NodeList集合不支持map方法。
    //让数组的map方法的this指向oLis对象,后面的函数是map()需要的参数。
    let newArr = Array.prototype.map.call(oLis,function(item,index){
        return item.innerHTML;
    })

    1.2.2 bind()

    ES5 IE9+,这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。

    适合需要反复调用函数的时候使用。

    let obj = {
        vip:0.8
    }
    
    //根据vip折扣打折
    function getSum(price,count){
        return (price * count) * this.vip;
    }
    //把getSum的this绑定到obj对象上,返回一个新的函数
    let getObjSum = getSum.bind(obj);
    //两个函数不相等,不是同一个函数
    console.log(getObjSum == getSum) //false
    console.log(getObjSum(20,100));
    
    //还可以先传一部分参数,再返回的函数中继续传后面的参数。
    function getSum(price,count){
        return (parseFloat(price) * count).toFixed(2) * this.vip;
    }
    //函数调用时只传递一部分参数进行调用,函数会返回一个新函数去处理剩下的参数,这是函数柯里化的应用
    let getObjSum = getSum.bind(obj,'20元');
    console.log(getObjSum(1000));

    2、举例

    验证数据输入合法性

        <div class="box">
            <div class="row">
                <span>输入0-1000的数字</span>
                <input id="num1">
                <span id="numtips1"></span>
            </div>
            <div class="row">
                <span>输入200-10000的数字</span>
                <input id="num2">
                <span id="numtips2"></span>
            </div>
        </div>
        <script>
            var oInput1 = document.querySelector('#num1');
            var oTips1 = document.querySelector('#numtips1');
            var oInput2 = document.querySelector('#num2');
            var oTips2 = document.querySelector('#numtips2');
    
            oInput1.oninput = function () {
                var result = checkNum.call(this,0,1000);
                oTips1.innerHTML = result;
            }
            oInput2.oninput = function () {
                var result = checkNum.call(this,200,10000);
                oTips2.innerHTML = result;
            }
    
            function checkNum(min, max) {
                return this.value >= min && this.value <= max ? '数据合法' : '数据不合法';
            }
        </script>
    //遍历学生的信息
    let students = [
        {
            name: 'mike',
            birth: '2010-10-15',
            city: '成都'
        },
        {
            name: 'daisy',
            birth: '2009-10-15',
            city: '重庆'
        },
        {
            name: 'Jone',
            birth: '2012-10-15',
            city: '北京'
        }
    ]
    // 遍历学生的信息
    students.forEach(function(item){
        // 把函数的this对象绑定在item对象上。
        printStudentInfo.call(item);
    })
    // 显示学生信息的函数
    function printStudentInfo(){
        let age = getAge(this.birth);
        console.log(`姓名是:${this.name},年龄是${age}岁,籍贯是:${this.city}`);
    }
    // 获得年龄的函数
    function getAge(birth){
        return new Date().getFullYear() - parseInt(birth);
    }


    点赞


    1
    保存到:

    相关文章

    发表评论:

    ◎请发表你卖萌撒娇或一针见血的评论,严禁小广告。

    Top