JS面试点- bind / call / apply
发布日期:2021-05-04 17:18:35 浏览次数:22 分类:精选文章

本文共 3710 字,大约阅读时间需要 12 分钟。

bind / call / apply 可用于this的显式绑定

this绑定的是 call,apply,bind 的第一个参数

call()方法

var a = {    user: 'zxx',    fn: function () {        console.log(this.user) // zxx    }}var b = a.fnb.call(a)

通过在call方法,第一个参数表示要把b添加到哪个环境中,简单来说,this就会指向那个对象。

call方法除了第一个参数以外还可以添加多个参数,如下

var a = {    user: 'zxx',    fn: function (x, xx) {        console.log(this.user) // zxx        console.log(x + xx) // 520    }}var b = a.fn

apply()方法

apply方法和call方法有些相似,它也可以改变this的指向

var a = {    user: 'zxx',    fn: function () {        console.log(this.user) // zxx    }}var b = a.fnb.apply(a)

同样apply也可以有多个参数,但是不同的是,第二个参数必须是一个数组,如下:

var a = {    user: 'zxx',    fn: function (x, xx) {        console.log(this.user) // zxx        console.log(x + xx) // 520    }}var b = a.fn

bind()方法

bind方法和call、apply方法有些不同,但是不管怎么说它们都可以用来改变this的指向。

先看下面一段代码:

var a = {    user:"zxx",    fn:function(){        console.log(this.user);    }}var b = a.fn;b.bind(a);

我们发现代码没有被打印,对,这就是bind和call、apply方法的不同,实际上bind方法返回的是一个修改过后的函数。不会立即调用,而是将函数返回

var a = {    user:"zxx",    fn:function(){        console.log(this.user); // zxx    }}var b = a.fn;var c = b.bind(a);c();

如果要调用的话必须还要加上()

同样bind也可以有多个参数,并且参数可以执行的时候再次添加,但是要注意的是,参数是按照形参的顺序进行的。

var a = {    user:"zxx",    fn:function(e,d,f){        console.log(this.user); // zxx         console.log(e,d,f); // 10 1 2    }}var b = a.fn;var c = b.bind(a,10);c(1,2);
回调函数的中使用bindvar obj = {    name: 'zxx'}setTimeout(function () {    console.log(this) // Object {name: "zxx"}}.bind(obj), 1000)========var obj = {    name: 'zxx'}setTimeout(function () {    console.log(this) // Window}, 1000)

如果你把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind,这些值在调用时会被忽略,实际应用的是默认绑定规则:

var a = {    user:"zxx",    fn:function(){        console.log(this); // Window    }}var b = a.fn;b.apply(null);

总结:call和apply(参数为数组)都是改变上下文中的this并立即执行这个函数,bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加,这是它们的区别。

bind方法

  • 对于普通函数,绑定this指向
  • 对于构造函数,要保证原函数的原型对象上的属性不能丢失
Function.prototype.bind = function (context, ...args) {    // 异常处理    if (typeof this !== "function") {      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");    }    // 保存this的值,它代表调用 bind 的函数    var self = this;    var fNOP = function () {};    var fbound = function () {        self.apply(this instanceof self ?             this :             context, args.concat(Array.prototype.slice.call(arguments)));    }    fNOP.prototype = this.prototype;    fbound.prototype = new fNOP();    return fbound;}

也可以这么用 Object.create 来处理原型:

Function.prototype.bind = function (context, ...args) {    if (typeof this !== "function") {      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");    }    var self = this;    var fbound = function () {        self.apply(this instanceof self ?             this :             context, args.concat(Array.prototype.slice.call(arguments)));    }    fbound.prototype = Object.create(self.prototype);    return fbound;}

 模拟实现call方法

Function.prototype.call = function (context) {    let context = context || window;    let fn = Symbol('fn');    context.fn = this;    let args = [];    for(let i = 1, len = arguments.length; i < len; i++) {        args.push('arguments[' + i + ']');    }    let result = eval('context.fn(' + args +')');    delete context.fn    return result;}

ES6 的语法

Function.prototype.call = function (context, ...args) {  let context = context || window;  let fn = new Symbol('fn');  context.fn = this;  let result = eval('context.fn(...args)');  delete context.fn  return result;}

apply方法

Function.prototype.apply = function (context, args) {  let context = context || window;  context.fn = this;  let result = eval('context.fn(...args)');  delete context.fn  return result;}

 

上一篇:在考虑闭包的情况下JS变量存储在栈与堆的区分
下一篇:将多层级数组转化为一级数组(即提取嵌套数组元素最终合并为一个数组)

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月14日 11时59分16秒