当前位置:首页 > Web开发 > 正文

args.concat(params));console.log(this);};fn_.prototype = fn

2024-03-31 Web开发

在 js 实现call和apply要领 一文中,我们详细分析并模拟实现了call/apply要领,由于篇幅问题,关于bind要领实现只能另起一篇。

在模拟bind之前,我们先了解bind的观点,这里引入解释:

bind() 要领创建一个新的函数,在 bind() 被挪用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供挪用时使用。

说的通俗一点,bind与apply/call一样都能转变函数this指向,但bind并不会当即执行函数,而是返回一个绑定了this的新函数,你需要再次挪用此函数才华到达最终执行。

我们来看一个简单的例子:

var obj = { z: 1 }; var obj1 = { z: 2 }; function fn(x, y) { console.log(x + y + this.z); }; // call与apply fn.call(obj, 2, 3); //6 fn.apply(obj, [2, 3]); //6 var bound = fn.bind(obj, 2); bound(3); //6 //测验考试改削bind返回函数的this bound.call(obj1, 3); //6

可以到bind并不是当即执行,而是返回一个新函数,且新函数的this无法再次被改削,我们总结bind的特点:

可以改削函数this指向。

bind返回一个绑定了this的新函数`boundFcuntion,例子中我们用bound暗示。

撑持函数柯里化,我们在返回bound函数时已通报了部分参数2,在挪用时bound补全了残剩参数。

boundFunction的this无法再被改削,使用call、apply也不行。

考虑到有的同学对付柯里化的陌生,所谓函数柯里化其实就是在函数挪用时只通报一部分参数进行挪用,函数会返回一个新函数去措置惩罚惩罚剩下的参数,一个经典简单的例子:

//函数柯里化 function fn(x, y) { return function (y) { console.log(x + y); }; }; var fn_ = fn(1); fn_(1); //2 fn(1)(1) //2

不难发明函数柯里化使用了闭包,在执行内层函数时,它使用了外层函数的局部形参x,从而组成了闭包,扯远了点。

我们来测验考试实现bind要领,先从简单的转变this和返回函数开始。

贰 ? 实现bind

之前已经有了模拟call/apply的经验,这里直接给出版本一:

Function.prototype.bind_ = function (obj) { var fn = this; return function () { fn.apply(obj); }; }; var obj = { z: 1 }; function fn() { console.log(this.z); }; var bound = fn.bind_(obj); bound(); //1

独一需要留意的就是var fn = this这一行,如果不提前生存,在执行bound时内部this会指向window。

版本一以满足了this改削与函数返回,顿时有同学就想到了,版本一不撑持函数传参,那么我们进行简单改削让其撑持传参:

Function.prototype.bind_ = function (obj) { //第0位是this,所以得从第一位开始裁剪 var args = Array.prototype.slice.call(arguments, 1); var fn = this; return function () { fn.apply(obj, args); }; };

完美了吗?并不完美,别忘了我们前面说bind撑持函数柯里化,在挪用bind时可以先通报部分参数,在挪用返回的bound时可以补全残剩参数,所以还得进一步措置惩罚惩罚,来看看bind_第二版:

Function.prototype.bind_ = function (obj) { //第0位是this,所以得从第一位开始裁剪 var args = Array.prototype.slice.call(arguments, 1); var fn = this; return function () { //二次挪用我们也抓取arguments东西 var params = Array.prototype.slice.call(arguments); //注意concat的挨次 fn.apply(obj, args.concat(params)); }; }; var obj = { z: 1 }; function fn(x, y) { console.log(x + y + this.z); }; var bound = fn.bind_(obj, 1); bound(2); //4

看,转变this,返回函数,函数柯里化均已实现。这段代码需要注意的是args.concat(params)的挨次,args在前,因为只有这样才华让先通报的参数和fn的形参按挨次对应。

至少走到这一步都挺挨次,需要注意的是,bind要领还有一个少见的特性,这里引用MDN的描述

绑定函数也可以使用 运算符结构,它会表示为方针函数已经被构建完毕了似的。供给的 this 值会被忽略,但前置参数仍会供给给模拟函数。

说通俗点,通过bind返回的boundFunction函数也能通过new运算符结构,只是在结构过程中,boundFunction已经确定的this会被忽略,且返回的实例还是会担任结构函数的结构器属性与原型属性,并且能正常接收参数。

有点绕口,我们来看个简单的例子:

var z = 0; var obj = { z: 1 }; function fn(x, y) { this.name = '听风是风'; console.log(this.z); console.log(x); console.log(y); }; fn.prototype.age = 26; var bound = fn.bind(obj, 2); var person = new bound(3);//undefined 2 3 console.log(person.name);//听风是风 console.log(person.age);//26

在此例子中,我们先是将函数fn的this指向了东西obj,从而得到了bound函数。紧接着使用new操纵符结构了bound函数,得到了实例person。不难发明,除了先前绑定好的this丢掉了(后面会解释原因),结构器属性this.name,以及原型属性fn.prototype.age都有顺利担任,除此之外,两个形参也告成通报进了函数。

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/web/31861.html