简要谈谈javascriptbind方法

骨月枫      2022-02-13     389

关键词:

  最近去参加了场面试,跟面试官聊了很多JS基础上的东西,其中有个问题是谈谈对apply、call、bind的理解和区别。顿时一愣,apply、call我知道,经常用的东西,bind是什么鬼!!!好像见过,也瞅过类似的文章,但是...不记得了...难道和jQuery的事件绑定的bind一样...

  既然不知道,那就整理总结下啰~

 

一、apply和call

  既然提到提到了这两兄弟,也跟着简单做下知识整理。在javascript中,this的指向是一个经常要处理的问题。比较经典的一个问题就是,document.getElementById太长了,敲着好累好烦,用一个短点的方法,对它进行封装一下,就下面这样,两行代码搞定,多么简单~

<div id="test"></div>
<script>
    var getDom = document.getElementById;
    console.log(getDom("test"))
</script>

但是。。。调用时,系统提示Uncaught TypeError: Illegal invocation 啊..........这是什么鬼错误 !其实这就是this的问题,使用document.getElementById,函数执行时this指向document,但是使用getDom,函数执行时,this指向的是window。而在getElementById在内核实现中又使用了this,so 就报错了啰!!!

正确的封装方式为:(即用apply/call设定下函数调用时的this指向)

<div id="test"></div>
<script>
var getDom = (function(func){
    return function(){
        return func.apply(document , arguments);
    }
})(document.getElementById);
console.log(getDom("test"))
</script>

  总结:apply和call的用法是一致的,就是改变和确定函数执行时的this指向,区别就是apply后一个参数是数组,call后是一堆参数。话不多说,进入正题....

 

二、bind基本

首先来谈谈它跟apply/call的区别,bind方法返回的是一个函数,不会立即执行,待用()调用时才会执行,而apply/call则是立即执行函数。

MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

接下来用demo简单使用下

1、单纯的绑定this

var person1 = {
    name : "sky" ,
    getName : function(){
        return this.name;
    }
}
var person2 = {name : "moon"};
var getName = person1.getName.bind(person2);        //绑定person2作为getName函数执行的this
console.log(getName());            //打印的值为moon

这样用法比较简单

 

2、传参数的形式

var self = {name : "sky" , age: 26}
var getDescription = function(country , city){
    console.log("my name is " + this.name + " , my age is " + this.age + " , I'am from " + country + " " + city);
}.bind(self , "China");
getDescription("WuHan");            //my name is sky , my age is 26 , I'am from China WuHan

个人感觉,这种就是相当于通过bind方法预设一些参数,比如此时就是预设的country参数,调用时在传递动态的参数,比如这里的WuHan。通过这样的方式绑定this,配合预设参数,灵活程度十分的高

 

三、bind的使用场景

水平有限,仅谈谈个人。我在多层函数嵌套的代码编写中,喜欢使用var _this = this;来保存上级函数作用域中的this,这样在内嵌的函数中就是可以用_this获取上级作用域的this。如果用bind则可以换一种方式,具体对比如下:

<div id="test1">test1</div>
<div id="test2">test2</div>
<script>
    //旧写法,使用_this保存
    var tool1 = {
        name: "sky1",
        bindEvent: function() {
            var _this = this;
            document.getElementById("test1").addEventListener("click", function() {
                console.log(_this.name)
            }, false)
        }
    }
    //新写法,使用bind绑定
    var tool2 = {
        name: "sky2",
        bindEvent: function() {
            document.getElementById("test2").addEventListener("click", function() {
                console.log(this.name)
            }.bind(this), false)
        }
    }
    tool1.bindEvent();
    tool2.bindEvent();
</script>

怎么说呢,代码看起来更加优美一些把....我是颜值控

 

四、bind 兼容性

bind方法是ES5中扩展的方法,所以IE6、7、8均不兼容...整个人都不好了

怎么办呢,网上有一堆的兼容资料,我比较喜欢自己造轮子...其实也蛮简单的,就是apply/call的封装使用,学习嘛,循序渐进的来,分成两步,以下均用skyBind方法表示...

1、仅仅实现修改执行环境即this的功能

Function.prototype.skyBind = function(context){
    var func = this;        //就是它!!!这个func就是需要执行,且要绑定context的函数!!!!!!
    return function(){
        return func.apply(context , arguments);            //绑定且执行
    }
}
var person1 = {
    name : "sky" ,
    getName : function(){
        return this.name;
    }
}
var person2 = {name : "moon"};
var getName = person1.getName.skyBind(person2);      
console.log(getName());            //打印的值为moon    

很简单有没有!!!

 

2、加入传参的功能

Function.prototype.skyBind = function(){
    var func = this  ,    //还是它!!!这个func就是需要执行,且要绑定context的函数!!!!!!
        context = [].shift.call(arguments) ,            //此时传入的参数就不单单有this的指向,还是其他的参数,按规定第一个参数就是执行环境,拿到它
        args = [].slice.call(arguments);                //arguments具有数组的属性,毕竟JS是个弱类型的语言,但是它毕竟不是数组,用这个方法就是把arguments转换成数组,不用slice换成splice或者其他的都行
    return function(){
        /* 绑定且执行,执行函数的参数为两个数组的合并
         * 这里需要解释的是args是bind绑定时传入的参数,比如下面demo中的China,而下面的arguments则是实际调用时传入的参数WuHan
         * */
        return func.apply(context , [].concat(args , [].slice.call(arguments) ));            
    }
}
//demo
var self = {name : "sky" , age: 26}
var getDescription = function(country , city){
    console.log("my name is " + this.name + " , my age is " + this.age + " , I'am from " + country + " " + city);
}.skyBind(self , "China");
getDescription("WuHan");            //my name is sky , my age is 26 , I'am from China WuHan

  

 搞定!!!

 

 

  

 

谈谈对多租户saas系统的简要理解

...计的核心关注点;本文作者详细介绍了多租户系统的简要理解,我们一起来看一下。SaaS领域一般都会涉及到租户的概念,在设计SaaS体系时,最重要的环节之一 查看详情

rpm与yum的简要介绍

   CentOS系统中,使用的软件管理机制为RPM机制,因为或多或少存在软件属性依赖的问题,所以作为在线升级的方式则为YUM。下面让我们来谈谈RPM与YUM的相关说明。    什么是RPM  RPM全名是"RedHat... 查看详情

简要异步方法执行方式

.net4.5及以后可以使用Task.Run(()=>{PrintText(requestData);});.net4.0及以前newThread(()=>{SendMail("",Email,"",msg);}).Start();  查看详情

谈谈常用清除浮动的方法

我们在做页面布局的时候,经常需要利用浮动来实现一些布局效果,这样带来的后果就会导致父元素丢失宽度。今天我们就来说说‘找回‘宽度的方法。而清除浮动后的效果应该是这样的请看:下面就说说方法,方法其实有非常... 查看详情

谈谈学习方法

上一篇文章公众号上有同学给我留言:张哥,我是一名大二学生,我很喜欢Android,但是我感觉我的逻辑思维有点慢,学习方法也不得巧,所以,问下您有什么建议吗?还是说我不适合学编程,大学计算机专业!其实不止这位同... 查看详情

简单谈谈js数组中的indexof方法

前言相信说到indexOf大家并不陌生,判断字符串是否包涵子字符串时特别常用,正则不熟练同学的利器。这篇文章就最近遇到的一个问题,用实例再说说说indexOf方法。本文是小知识点积累,不作为深入讨论的话题,因此这里没有... 查看详情

谈谈我对多态的理解?

举例:父类:Person{}  子类:ChildextendsPerson{}父类的引用指向子类的对象:Personp=newChild();理解:在编译期认为p是父类的对象,在运行期认为p是子类的对象 ////////////////////子类执行方法的情况:  1.子类重写了父类方法,... 查看详情

谈谈vector容器的三种遍历方法

说明:本文仅供学习交流。转载请标明出处。欢迎转载!?????vector容器是最简单的顺序容器,其用法相似于数组。实际上vector的底层实现就是採用动态数组。在编敲代码的过程中。经常会变量容器中的元素,那么怎样遍历这些元... 查看详情

结合css3的布局新特征谈谈常见布局方法

写在前面最近看到《图解CSS3》的布局部分,结合自己以前阅读过的一些布局方面的知识,这里进行一次基于CSS2、3的各种布局的方法总结。常见的页面布局在拿到设计稿时,作为一个前端人员,我们首先会做的应该是为设计图大... 查看详情

javascript基础简要

JavaScript 引用外部js :  <scriptsrc="2.js"type="text/javascript"></script>Java是一门弱类型的语言;变量的声明用var全局变量:1.在方法外声明的变量;        2.在方法内声明,没 查看详情

java核心技术36讲----------谈谈finalfinallyfinalize有什么不同

一、final1.final修饰方法时,需要注意的点:  #final修饰方法时,之前的第二个原因是效率。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“  ... 查看详情

scss简要教程(常用指令与方法)

Sass是成熟、稳定、强大的CSS预处理器,而SCSS是Sass3版本当中引入的新语法特性,完全兼容CSS3的同时继承了Sass强大的动态功能。CSS书写代码规模较大的Web应用时,容易造成选择器、层叠的复杂度过高,因此推荐通过SASS预处理器... 查看详情

谈谈用自己的电脑能外网访问的方法

花生壳,注册账号,并买个基本套餐,每月1G流量,1M带宽,可满足最基本的外网调试需求。ngrok,国外产的一个类似代理服务器的东西,然而我大天朝的墙实在太高了,国内外的流量想快速流通除非有特殊管道。natapp,ngrok的天... 查看详情

谈谈关于文件下载(代码片段)

昨天跟后端小哥调了调关于文件下载的接口,还是有一些坑的,这里总结一下。我们分为后端返回二进制流或者返回url的形式进行讲述。一、后端返回二进制流总的来说关于文件下载前端有以下两种方法去拉取数据:... 查看详情

谈谈关于文件下载(代码片段)

昨天跟后端小哥调了调关于文件下载的接口,还是有一些坑的,这里总结一下。我们分为后端返回二进制流或者返回url的形式进行讲述。一、后端返回二进制流总的来说关于文件下载前端有以下两种方法去拉取数据:... 查看详情

android中imageview显示图片的几种方法简要分析(代码片段)

我们知道,对于Imageview显示图片,常用的有一下几种方式 imaegView.setImageBitmap(); imaegView.setImageResource(); imaegView.setImageDrawable(); imaegView.setImageURI(); imaegView.setBackground(); imaegView.setB 查看详情

android中imageview显示图片的几种方法简要分析(代码片段)

我们知道,对于Imageview显示图片,常用的有一下几种方式 imaegView.setImageBitmap(); imaegView.setImageResource(); imaegView.setImageDrawable(); imaegView.setImageURI(); imaegView.setBackground(); imaegView.setB 查看详情

android中imageview显示图片的几种方法简要分析(代码片段)

我们知道,对于Imageview显示图片,常用的有一下几种方式 imaegView.setImageBitmap(); imaegView.setImageResource(); imaegView.setImageDrawable(); imaegView.setImageURI(); imaegView.setBackground(); imaegView.setB 查看详情