js中的function对象

70 阅读2分钟
 * 每个javascript函数实际上都是一个Function对象。运行
 *  (function(){}).constructor === Function // true 便可以得到这个结论.
// 构造函数
const Rectangle = new Function('a', 'b', 'return a+b')
// console.log(Rectangle, Rectangle(1, 2)) // anonymous 3

// 实例属性
// console.log(Rectangle.prototype.arguments) // undefined已弃用, 推荐使用函数内部的arguments
// console.log(Rectangle.prototype.caller) // undefined已弃用, 
// console.log(Rectangle.prototype.displayName) // 函数的显示名称(描述)
// console.log(Rectangle.prototype.length) // 函数形参
// console.log(Rectangle.prototype.name, '---') // 函数的名称

/**
 * 实例方法
 */
{
    /**
     * apply
     *      语法:
     *          apply(thisArg) 
     *          apply(thisArg, argsArray)
     *      参数:
     *          thisArg,在func函数运行时使用this值。请注意,this可能不是该方法看到的实际值:
     *          如果这个函数处于非严格模式下,若指定为null或undefined时会自动替换为全局对象,原始值会被包装。
     *          argsArray(可选),一个数组或类数组对象,其中的数组元素将作为单独的参数传给func函数。如果该参数的值为
     *          null或undefined,则表示不需要传入任何参数。
     *      返回值:
     *          调用有指定this值和参数的函数的结果
     *      描述:
     *          apply与call用法几乎相同,唯一区别就是apply接受一个单独数组或者类数组(尽量转为数组),call接受一个参数列表
     */
    // 示例
    //      1.用apply将数组各项添加到另一个数组
    {
        let arr = [1, 2, 3]
        let elements = [4, 5, 6]
        arr.push.apply(arr, elements)
        // console.log(arr)
    }

    {
        // 原始做法
        let arr = [1, 2, 3]
        let elements = [4, 5, 6]
        arr.push(...elements)
        // console.log(arr)
    }

    /*示例
        2.使用apply和内置函数
     */
    {
        let arr = [3, 4, 1, 2, 0.2]
        // console.log(Math.max(...arr), Math.max.apply(null, arr)) // 4 4
        // console.log(Math.min(...arr), Math.min.apply(null, arr)) // 0.2 0.2
    }

    {
        // 简单循环算法
        let arr = [3, 4, 12, 1, 2, 0.2],
            max = -Infinity,
            min = +Infinity
        for (let i = 0; i < arr.length; i ++) {
            if (arr[i] > max) {
                max = arr[i]
            }
            if (arr[i] < min) {
                min = arr[i]
            }
        }
        // console.log(max, min)
    }

    /* 使用apply来链接构造器 */
    Function.prototype.construct = function (aArgs) {
        let oNew = Object.create(this.prototype)
        this.apply(oNew, aArgs)
        return oNew
    }
    
    function myConstruct() {
        for (let i = 0; i < arguments.length; i++) {
            this['property' + i] = arguments[i]
        }
    }

    let arr = ['hello', 'world', '!']
    let myInstance = myConstruct.construct(arr)
    console.log(myInstance)
    
}

{
    /**
     * call
     */
    // 示例1:使用call方法调用父构造函数
    {
        function Product(name, price) {
            this.name = name
            this.price = price
        }
        function Food(name, price) {
            Product.call(this, name, price)
            this.category = 'food'
        }

        let f = new Food('tea', 19)
        console.log(f.name, f.price)
    }

    // 示例2:使用call方法调用匿名函数
    {
        let arr = [
            {name: '张三', age: 18},
            {name: '李四', age: 19}
        ]
        for (let i = 0; i < arr.length; i++) {
            (function(i) {
                this.print = function() {
                    console.log(`我是第${i}个,name:${this.name}age:${this.age}`)
                }
            }).call(arr[i], i)
        }
        arr[0].print()
        arr[1].print()
    }
    // 示例3:使用call方法调用函数并且指定上下文的this
    {
        function say() {
            console.log('我的名字叫' + this.name)
        }

        let person = {
            name: '张三'
        }

        say.call(person)
    }
    // 示例4:使用call方法调用函数并且不指定第一个参数(arguments)
    {
        var name = '张三'
        function say() {
            console.log('我的名字叫' + this.name)
        }

        say.call()
    }
}

{
    /**
     * bind
     *     语法:
     *          function.bind(thisArg, [arg1,...])
     *      参数:
     *          thisArg,调用绑定函数时作为this参数传递给目标函数的值。如果使用new运算符构造绑定函数,则忽略该值。
     *          当使用bind在setTimeout中创建一个函数作为回调提供时,作为thisArg传递的任何原始值都将转换为Object。
     *          如果bind函数的参数列表为空,或者thisArg是null或undefined,执行作用域的this将被视为新函数的thisArg。
     *          arg1, arg2,当目标函数被调用时,被预置入绑定函数的参数列表中的参数。
     *      返回值
     *          返回一个原函数的拷贝,并拥有指定的this值和初始参数。
     *      描述
     *         创建一个新函数,该函数包装了原函数对象,
     */
    /* 示例:创建绑定函数 */
    {
        window.x = 90
        const module  = {
            x: 81,
            getX: function() {
                console.log(this.x)
            }
        }

        // module.getX()
        const retrieveX = module.getX
        // retrieveX()
    }
    {
        window.x = 90
        const module  = {
            x: 81,
            getX: function() {
                console.log(this.x)
            }
        }

        module.getX()
        const retrieveX = module.getX
        const a = retrieveX.bind(module)
        a()
    }
    /* 拥有预设参数 */
    {
        function list() {
            return Array.prototype.slice.call(arguments)
        }

        let arr = list(1, 2, 3)
        let arr1 = list.bind(null, 90) // 预设参数
        console.log(arr1(1, 2, 3))
        console.log(arr)
    }
    /* 配合setTimeout */
    function LateBloomer() {
        this.petalCount = Math.ceil(Math.random() * 12) + 1
    }
    LateBloomer.prototype.bloom = function () {
        window.setTimeout(this.declare.bind(this), 1000)
    }
    LateBloomer.prototype.declare = function() {
        console.log(`i am a beautiful flower with ${this.petalCount} petals!`)
    }

    /* 快捷调用 */
    {
        function f() {
            let slice = Array.prototype.slice.apply(arguments)
            let slice1 = [].slice.apply(arguments)
            console.log(slice, slice1)
        }
        f(1, 2, 3)
    }
}