在实际开发过程中,对于函数封装时,不确定外部是谁调用的,调用函数内部方法时,有可能是window调用这时就会报错,常使用callapply,bind来绑定this指向。

Function.prototype.call()

call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数。

该方法和apply()类似,区别在于,call()可以接收若干参数,而apply()接收的是一个包含多个参数的数组。

语法:fun.call(thisArg, arg1, arg2, ...)

call 可以继承

通过父类的构造函数call方法实现继承

function Product(name, price) {this.name = name;this.price = price;}function Food(name, price) {Product.call(this, name, price);this.category = 'food';}var cheese = new Food('feta', 5);console.log(cheese)// Food { name: 'feta', price: 5, category: 'food' }
复制代码

实例都会拥有在Product构造函数中添加的name属性和price属性,但category属性是在各自的构造函数中定义的。

call 方法调用匿名函数

var animals = [{ species: 'Lion', name: 'King' },{ species: 'Whale', name: 'Fail' }];for (var i = 0; i < animals.length; i++) {(function(i) {console.log('#' + i + ' ' + this.species + ': ' + this.name) }).call(animals[i], i);}
复制代码

for循环体内,我们创建了一个匿名函数,然后通过调用该函数的call方法,将每个数组元素作为指定的this值执行了那个匿名函数。

call方法指定上下文的this

function greet() {var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');console.log(reply);
}
var obj = {animal: 'cats', sleepDuration: '12 and 16 hours'
};
greet.call(obj);
// cats typically sleep between 12 and 16 hours
复制代码

Function.prototype.apply()

apply()调用一个指定this值的函数, 接收作为一个数组或者类数组对象提供的参数

语法: func.apply(thisArg, [argsArray])

apply 将数组添加到另一个数组

var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.log(array); // ["a", "b", 0, 1, 2]
复制代码

apply 找出最大值和最小值

var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers)
var min = Math.min.apply(null, numbers);
复制代码

如果参数组非常大,将参数数组切块后,循环传入目标方法:

function minOfArray(arr) {var min = Infinity;var QUANTUM = 32768;for (var i = 0, len = arr.length; i < len; i += QUANTUM) {var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));min = Math.min(submin, min);}return min;}var min = minOfArray([5, 6, 2, 3, 7]);console.log(min) // 2
复制代码

Function.prototype.bind()

bind()方法创建一个新函数, 在调用时设置this关键字为提供的值。

并在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项。 语法: function.bind(thisArg, [arg1[, arg2[, ...]]])

创建绑定函数

his.x = 9;    // 在浏览器中,this指向全局的 "window" 对象
var module = {x: 81,getX: function() { return this.x; }
};
module.getX(); // 81
var retrieveX = module.getX;
retrieveX(); // 返回9 - 因为函数是在全局作用域中调用的var boundGetX = retrieveX.bind(module);  // 创建一个新函数,把 'this' 绑定到 module 对象
boundGetX(); // 81
复制代码

偏函数

function list() {return Array.prototype.slice.call(arguments);
}function addArguments(arg1, arg2) {return arg1 + arg2
}var list1 = list(1, 2, 3); // [1, 2, 3]var result1 = addArguments(1, 2); // 3// 创建一个函数,它拥有预设参数列表。
var leadingThirtysevenList = list.bind(null, 37);// 创建一个函数,它拥有预设的第一个参数
var addThirtySeven = addArguments.bind(null, 37); var list2 = leadingThirtysevenList();
// [37]var list3 = leadingThirtysevenList(1, 2, 3);
// [37, 1, 2, 3]var result2 = addThirtySeven(5);
// 37 + 5 = 42 var result3 = addThirtySeven(5, 10);
// 37 + 5 = 42 ,第二个参数被忽略
复制代码

Call原理

Function.prototype.myCall = function(context) {context = context ? Object(context) : windowcontext.fn = thislet args = [...arguments].slice(1)let r = context.fn(args)delete context.fnreturn r
}
复制代码

fn1.myCall(fn2)时,绑定当前this 需要context.fn = this等价于context.fn = fn1 调用的时候 context.fn() 等价于 fn2.fn()此时thisfn2 并执行fn1

fn1.myCall.myCall(fn2)是此时都是执行myCall函数, thiswindow, 并执行fn2函数。

apply原理

Function.prototype.myApply = function(context) {context = context ? Object(context) : windowcontext.fn = thislet args = [...arguments[1]]if (!args) {return context.fn()}let r = context.fn(args)delete context.fn;return r}
复制代码

bind原理


let obj = {name: 'joker'
}function fn() {console.log(this.name)
}
Function.prototype.bind = function(context) {}
let bindFn = fn.bind(obj)
bindFn()
// joker
复制代码

从上面例子可以看出

  1. bind可以绑定this执行为传入的对象
  2. bind方法返回一个函数(高阶函数) 实现一个简易的bind方法
Function.prototype.bind = function(context) {let _me = thisreturn function() {return _me.apply(context)}
}
复制代码

bind 还可以多次传参 用法:

let obj = {name: 'joker'
}function fn(name, age) {console.log(this.name + '今年' + name + age + '岁了')
}
let bindFn = fn.bind(obj, '大概')
bindFn(10)
// joker今年大概10岁了
复制代码

绑定this的时候传递了一个值, 执行bindFn又传了一个参数,因此之前的函数需要改造

Function.prototype.bind = function(context) {let _me = thislet bindArgs = [].slice.call(arguments, 1) // 获取bind方法传入的参数return function() {let fnArgs = [].slice.call(arguments) // 获取函数执行传入的参数return _me.apply(context, bindArgs.concat(fnArgs))}
}
复制代码

如果当前绑定的函数被new了,当定函数中的this 是当前函数的实例,用法

let obj = {name: 'joker'
}
function fn(name, age) {console.log(this)  //  this是fn
}
let bindFn = fn.bind(obj)
let instance = new bindFn()
复制代码

那么这个方法还需要改造一下, 如果当前函数执行中的thisfBound的实例,说明是new执行的,那么当前 this就是函数的实例,否则是context

Function.prototype.bind = function(context) {let _me = thislet bindArgs = [].slice.call(arguments, 1)function Fn() {}let fBound = function() {let fnArgs = [].slice.call(arguments)return _me.apply(this instanceof fBound ? this : context, bindArgs.concat(fnArgs))}Fn.prototype = this.prototypefBound.prototype = new Fn();return fBound
}
复制代码

call,apply,bind,new实现原理相关推荐

  1. JavaScript内置一些方法的实现原理--new关键字,call/apply/bind方法--前戏

    new关键字,call/apply/bind方法都和this的绑定有关,在学习之前,首先要理解this. 一起来学习一下this吧 首先.this是一个对象. 对象很好理解,引用类型值,可以实现如th ...

  2. 50行javaScript代码实现简单版的 call , apply ,bind 【中级前端面试基础必备】

    在实现自己的call,apply,bind前,需要复习一下this. ###所谓的this其实可以理解成一根指针: 其实 this 的指向,始终坚持一个原理:this 永远指向最后调用它的那个对象,这 ...

  3. call(),apply(),bind()的用法及举例

    通过学习call(),apply(),bind()的用法和区别,我们能更好的理解this及作用域的含义,为后面的编程打下基础. call()的用法: 调用一个函数,使其具有一个指定的this值和分别地 ...

  4. 复习javascript中call,apply,bind的用法

    一直很难理解js中的call apply bind,在w3schools,mdn阅读了,也看了很多相关的文章,今天我来写下我理解的call apply bind 首先创建一个函数 function m ...

  5. call / apply / bind

    对于 call / apply / bind 来说,他们的首要目的是用于改变执行上下文的 this 指针. call / apply 对 call / apply 的使用,一般都如下,用于改变执行环境 ...

  6. call() , apply() ,bind()的用法

    call() , apply() ,bind()的用法 - 作用:改变this指向,可以传递参数 - 语法: A.call(B, 参数1, 参数2)A.apply(B, [ 参数1, 参数2])A.b ...

  7. JavaScript中的call,apply,bind学习总结

    JavaScript 中的 call, apply, bind 这三个函数的作用和区别在各大论坛都被讨论了很多次了,但是我一直都还没来得及好好总结,这次正好看到了一个很不错的关于JavaScript ...

  8. JavaScript中call,apply,bind方法的总结。

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = {user:"追梦子",fn:fun ...

  9. call apply bind 的作用和区别

    1.call apply bind 的作用和区别 作用: 都可以改变函数内部的this指向. 区别点: 1.call和apply会调用函数,并且改变函数内部this指向. 2.call和apply传递 ...

最新文章

  1. 一百年后,人类怎样编程?
  2. 2010 eWEEK 年度产品
  3. 15 错误边界与使用技巧
  4. 常用数据库的分页实现
  5. Java RandomAccessFile getFilePointer()方法与示例
  6. Flink - allowedLateness
  7. r语言pls分析_R语言:生存分析
  8. 为什么办理房产证要经过开发商和物业?
  9. 微信和QQ可以关闭广告了,每次能关6个月
  10. 智能优化算法:象群算法-附代码
  11. 引入网易云音乐播放器卡片
  12. Python 自动化测试 必会模块 Unittest
  13. D3.js中文版api-接口文档
  14. 【python】王者荣耀全英雄高清壁纸爬虫共467M(多线程)
  15. 记一次服务器被木马注入攻击
  16. AP系列文章——PDM麦克风
  17. 任正非霸气回应:没有谷歌,华为也能成为世界第一!
  18. hdu2097 Sky数
  19. python3个引号啥意思_Python中单引号,双引号,3个单引号及3个双引号的区别
  20. mysql查看密码_如何查看mysql数据库用户密码?

热门文章

  1. 《游戏设计师修炼之道:数据驱动的游戏设计》一1.4小结
  2. 通过反射获取子类和父类定义的属性
  3. lua 函数调用1 -- 闭包详解和C调用
  4. PHP命名规范【转】
  5. Windows程序设计零基础自学_7_进程操作
  6. 更改innodb_page_size状态值
  7. ADSL防御******的十大方法
  8. go语言设计模式 - 建造者模式
  9. WEB API的安全问题
  10. uestc 250 数位dp(水)