自学内容网 自学内容网

JS手写call,apply,bind方法

这三个方法的作用说白了就是改变this指向,非常简单,但是手写需要搞清楚原理。

这里用call作为例子

var test = {
    value: 11
}

function bar() {
    console.log(this.value)
}

bar.call(test) //11

call改变了this指向,指向了test

bar函数执行

手写模拟这种效果,怎么将bar的this指向test呢?

var test = {
    value: 11,
    function bar() {
        console.log(this.value)
    }
}

test.bar()

这样效果便和上面一样了,但是白白给test加了一个属性这是不行的,所以最后需要删除它。

所以模拟步骤可以分为三步:

1.将函数设为对象的属性

2.执行函数

3.删除函数

所以代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        Function.prototype.call2 = function(context) {
            context.fn = this  //this指向调用者,结合下文即为bar
            context.fn()  //指向函数
            delete context.fn  //删除函数
        }

        var test = {
            value: 11
        }

        function bar() {
            console.log(this.value)
        }

        bar.call2(test)  //11
    </script>
</body>
</html>

但是仔细一想call函数是可以传参的,于是稍作修改:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        Function.prototype.call2 = function(context) {
            context.fn = this
            let rest = [...arguments].slice(1) //用slice方法获取第二个开始的参数作为参数数组
            let result = context.fn(...rest)  //传参数组
            delete context.fn
        }

        var test = {
            value: 11
        }

        function bar(name, age) {
            console.log(name)
            console.log(age)
            console.log(this.value)
        }

        bar.call2(test,'lwhdsb',18)
        //lwhdsb
        //18
        //11
    </script>
</body>
</html>

使用arguments属性和slice方法可以截取数组

需要注意

this传null或者undefined时,将是window,(node环境是global)

函数有返回值

所以再次稍作修改

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        Function.prototype.call2 = function(context) {
            if(!context){
                context = typeof window === 'undefined' ? global : window
            }
            context.fn = this
            let rest = [...arguments].slice(1) //用slice方法获取第二个开始的参数作为参数数组
            let result = context.fn(...rest)  //传参数组
            delete context.fn
            return result
        }

        var test = {
            value: 11
        }

        function bar(name, age) {
            console.log(name)
            console.log(age)
            console.log(this.value)
        }

        bar.call2(test,'lwhdsb',18)
        //lwhdsb
        //18
        //11
    </script>
</body>
</html>

就是最终版本,其他两个也和这个思路大差不差,就省略了


原文地址:https://blog.csdn.net/2301_80659102/article/details/142375754

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!