手把手教你实现三种绑定方式(call、apply、bind)
关于绑定首先要说下this的指向问题。
我们都知道:
函数调用时this指向window
对象调用函数时this指向对象本身
看下面得例子:
- // 1
- function test(){
- const name = 'test1';
- console.log(this.name)
- }
- constname = 'test2'
- test() // test2
- // 当前函数调用指向了window,所以打印的为test2
- // 2
- var obj = {
- name:'test1',
- get(){
- console.log(this.name)
- }
- }
- var name = 'test2';
- obj.get() // test1
- // 当前通过对象调用。this指向obj,打印test1
- // 3
- var obj = {
- name:'test1',
- get(){
- console.log(this.name)
- }
- }
- var name = 'test2';
- var fn = obj.get;
- fn() // test2
- // 将obj.get作为值赋值给fn,执行fn,这时候相当于通过函数执行,this重新指向
那如何将this指向到我们指定的对象中呢?
js提供改变this指向的三种方法:call、apply、bind
其中call和apply执行改变this的同时会执行函数,bind是会返回一个函数。
而call与apply的区别在于参数,call可以传多个参数,而apply传一个数组作为参数。下面来看看实现:
模拟实现call
- Function.prototype.myCall = function(thisArg, ...argumentArr){
- if(typeof this !== 'function') {
- throw new TypeError(`${this} is not function`)
- };
- if(thisArg === undefined || thisArg === null){
- thisArg = window;
- }
//生成一个对象- var obj = Object.create(thisArg)
- obj['fn'] = this;
// 通过对象执行函数将this指向该对象- var result = obj['fn'](...argumentArr)
- delete obj['fn'];
- return result
- }
- var obj = {
- name:'test1',
- get(data1, data2){
- console.log(this.name, data1, data2)
- }
- }
- obj.get.myCall({name: 'test2'}, 1, 2, 3) // test2,1,2
- // 原理就是通过传入的新的对象来执行这个函数,就是通过对象调用函数的方式
模拟实现apply
- Function.prototype.myApply = function(thisArg, argumentArr){
- if(typeof this !== 'function') {
- throw new TypeError(`${this} is not function`)
- };
- if(thisArg === undefined || thisArg === null){
- thisArg = window;
- }
- if(argumentArr === undefined || argumentArr === null){
- argumentArr = []
- }
- var obj = Object.create(thisArg)
- obj['fn'] = this;
- var result = obj['fn'](...argumentArr)
- delete obj['fn'];
- return result
- }
- var obj = {
- name:'test1',
- get(data1, data2){
- console.log(this.name, data1, data2)
- }
- }
- obj.get.myApply({name: 'test2'}, [1, 2, 3]) // test2,1,2
- // 我们发现与call唯一的不同就是入参,call使用rest 参数,将多余的参数整合成argument形式,而apply入参直接是数组
模拟实现bind
- Function.prototype.myBind = function(thisArg, ...argumentArr){
- if(typeof this !== 'function') {
- throw new TypeError(`${this} is not function`)
- };
- if(thisArg === undefined || thisArg === null){
- thisArg = window;
- }
- var self = this
- var bindfn = function(){
- return self.call(thisArg, ...argumentArr)
- }
- bindfn.prototype = self.prototype
- return bindfn
- }
- var obj = {
- name:'test1',
- get(data1, data2){
- console.log(this.name, data1, data2)
- }
- }
- const fn = obj.get.myBind({name: 'test2'}, 1, 2, 3)
- fn() // test2,1,2
- // 相比于前两个bind会有不一样,bind使用到了闭包,
- // 我们之前知道函数执行this是指向window,但是这里我们执行却指向了我们的目标对象,实现这样的方式就是闭包的原因
如果我们没有赋值操作执行var self = this,而是直接使用this执行的话
- this.call(thisArg, ...argumentArr)
这个时候this是指向window的,这个时候会报this.call is not a function。当我们进行赋值给self ,那么这个时候self 就形成了返回的函数fn的专属背包而不被销毁,每当我们执行fn的时候取到的this都是obj.get方法
手把手教你实现三种绑定方式(call、apply、bind)的更多相关文章
- v-bind绑定属性样式——class的三种绑定方式
1.布尔值的绑定方式 <div id="demo"> <span v-bind:class="{‘class-a‘:isA ,‘class-b‘:isB ...
- js this详解,事件的三种绑定方式
this,当前触发事件的标签 在绑定事件中的三种用法: a. 直接HTML中的标签里绑定 onclick="fun1()"; b. 先获取Dom对象,然后利用dom对象在js里绑定 ...
- Dom事件的三种绑定方式
1.事件 2. onclick, onblur, onfocus, 需求:请写出一个行为,样式,结构,相分离的页面. JS, CSS, HTML, 示例1,行为结构样式粘到一起的页面: & ...
- Binding 中 Elementname,Source,RelativeSource 三种绑定的方式
在WPF应用的开发过程中Binding是一个非常重要的部分. 在实际开发过程中Binding的不同种写法达到的效果相同但事实是存在很大区别的. 这里将实际中碰到过的问题做下汇总记录和理解. 1. so ...
- JavaScript三种绑定事件的方式
JavaScript三种绑定事件的方式: 1. <div id="btn" onclick="clickone()"></div> // ...
- AutoLayout的三种设置方式之——NSLayoutConstraint代码篇
AutoLayout是从IOS 6开始苹果引入来取代autoresizing的新的布局技术,该技术有三种设置方式,等下我来为大家一一叙述一下. 在说三种设置方式前,我们先简单的说一下autolayou ...
- JavaScript 三种绑定事件方式之间的区别
JavaScript三种绑定事件的方式: 1. <div id="btn" onclick="clickone()"></div> // ...
- Asp.Net中的三种分页方式
Asp.Net中的三种分页方式 通常分页有3种方法,分别是asp.net自带的数据显示空间如GridView等自带的分页,第三方分页控件如aspnetpager,存储过程分页等. 第一种:使用Grid ...
- Service组件 总结 + 绑定理Service三种实现方式 Messager + Binder + AIDL
在Android中进程按优先级可以分为五类,优先级从高到低排列: - 前台进程 该进程包含正在与用户进行交互的界面组件,比如一个Activity - 可视进程 该进程中的组件虽然没有和用户交互,但是仍 ...
随机推荐
- ListBox控件简单的数据绑定
<ListBox Margin="17,8,15,26" Name="ListBoxName" ItemsSource="{Binding Ta ...
- system分区解锁
前言 获取root权限,解锁system 步骤 手机设置 设置--更多设置--开发者选项--USB调试给打开 电脑操作 打开cmd adb devices 执行命令 adb root &&am ...
- featureCarousel.js 3d轮播图插件
jQuery Feature Carousel 插件是国外的一比较优秀的旋转木马图片插件. 点击这里进入原文. 插件特点: 1.处理div的3d旋转木马效果. 2.支持一个中心,2个侧面的功能 3.中 ...
- 【SpringMVC配置失效】Springboot2.x拦截器配置不无生效
一.环境 maven springboot版本2.x <parent> <groupId>org.springframework.boot</groupId> &l ...
- 常用的STL
map 容器和数组一样,不过比较活用,相当于直接离散化数组 map<int ,int>mp 一维int map<string ,string>mp 一维 str ma ...
- The 2014 ACM-ICPC Asia Mudanjiang Regional First Round C
题意: 这个是The 2014 ACM-ICPC Asia Mudanjiang Regional First Round 的C题,这个题目当时自己想的很复杂,想的是优先队列广搜,然后再在 ...
- 解决在Vim中鼠标右键不能粘贴问题
最近维护一台服务器,使用putty登录后,用vim时,鼠标右键不能 粘贴而是进入了visual模式.网上查找一番找到了解决方法: 方 法一:在普通模式下键入" :set mouse-=a&q ...
- PowerShell-4.API调用以及DLL调用
PowerShell可以直接调用API,So...这东西完全和cmd不是一回事了... 调用API的时候几乎和C#一样(注意堆栈平衡): 调用MessageBox: $iii = Add-Type - ...
- nodejs-安装/helloworld/npm
安装---------------------------------------------------------------- http://nodejs.cn/download/ 完成之后确定 ...
- StreamReader & StreamWriter
这节讲StreamReader & StreamWriter,这两个类用于操作字符或者字符串,它将流的操作封装在了底层,相对来说用法比较简单,但是它不支持Seek()方法. 先看一下代码: F ...