手动实现es5中的bind方法

前言

this的指向在javascript中一直是个谜同样的存在,可是不少地方又会用到this,因此理解和使用this很是重要,关于this的理解这篇文章不作介绍,由于这篇的目的是改变this的指向。javascript

改变this的指向有三种方法,call,apply,bind。下面先介绍下这三种方法java

改变this指向

call

var a = {
    name:"aaa",
    say(type){
        console.log(type,this.name);
    }
}
a.say("at");//at aaa
var tn = {name:"ttt"};
a.say.call(tn,"tt")//tt ttt

能够看到经过call,say方法中的this指向了tn,传参的方式的列举面试

apply

var a = {
    name:"aaa",
    say(type){
        console.log(type,this.name);
    }
}
a.say("at");
var tn = {name:"ttt"};
a.say.apply(tn,["tt"])

能够看到经过apply,say方法中的this指向了tn,传参的方式是数组数组

bind

bind也能改变this的指向,不过和call,apply不一样的地方在于,bind只改变this,不会指向函数app

var a = {
    name:"aaa",
    say(type){
        console.log(type,this.name);
    }
}
var tn = {name:"ttt"};
var b = a.say.bind(tn);
b();//ttt

bind 改变this,也是可以继承原型链的,看下下面的代码函数

var to = {name:"to",color:"red"};
function Animal(){
    console.log(`name:${this.name}...color:${this.color}`);
}
Animal.prototype.say = function(){
    console.log(`say..name:${this.name}...color:${this.color}`);
}
var Cat = Animal.bind(to);
Cat();//name:to...color:red
var cat = new Cat();// name:undefined...color:undefined
cat.say();//say..name:undefined...color:undefined

由于cat是Cat的实例,Cat是改变了this的Animal,因此cat也是Animal的实例,可是this是指向cat的,因此this.name是undefinedthis

实现bind

Function.prototype.bind = function(obj){
    const args = Array.prototype.slice.call(arguments,1);//保留bind时的参数
    const that = this;
    const bound =  function(){
        const inArgs = Array.prototype.slice.call(arguments);//执行bind的函数时的参数
        const newArgs = args.concat(inArgs);//组装参数
        that.apply(obj,newArgs);//执行bind的函数
    }
    //继承prototype--寄生组合式继承
    function F(){};
    F.prototype = that.prototype;
    bound.prototype = new F();
    return bound;
}

而后执行上面的代码es5

Cat();//name:to...color:red
var cat = new Cat();//name:to...color:red
cat.say();//say..name:undefined...color:undefined

不过第二行和原生的bind仍是有点区别的,这里仍是记住了以前的bind的对象,原生的不知道为啥是undefinedprototype

面试题

实现es5中的bind方法,使得下面的代码输出successcode

function Animal(name,color){
    this.name = name;
    this.color = color;
}
Animal.prototype.say = function(){
    return `i am a ${this.color} ${this.name}`
}
const Cat = Animal.bind(null,"cat");
const cat = new Cat("white");
if(cat.say() === 'i am a white cat' && cat instanceof Cat && cat instanceof Animal){
    console.log("success")
}

加上上面的bind实现,咦??没有出现success??为何?
分析一下代码,bind的第一个参数是null??null的时候应该默认为this,修改代码以下

Function.prototype.bind = function(obj){
    const args = Array.prototype.slice.call(arguments,1);//保留bind时的参数
    const that = this;
    const bound =  function(){
        const inArgs = Array.prototype.slice.call(arguments);//执行bind的函数时的参数
        const newArgs = args.concat(inArgs);//组装参数
        const bo = obj || this;
        that.apply(bo,newArgs);//执行bind的函数
    }
    //继承prototype--寄生组合式继承
    function F(){};
    F.prototype = that.prototype;
    bound.prototype = new F();
    return bound;
}

输出success完美~~~撒花~~~

相关文章
相关标签/搜索