call,apply,bind,new实现原理
在实际开发过程中,对于函数封装时,不确定外部是谁调用的,调用函数内部方法时,有可能是window
调用这时就会报错,常使用call
,apply
,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()
此时this
是fn2
并执行fn1
。
当fn1.myCall.myCall(fn2)
是此时都是执行myCall
函数, this
为window
, 并执行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
复制代码
从上面例子可以看出
- bind可以绑定
this
执行为传入的对象 - 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()
复制代码
那么这个方法还需要改造一下, 如果当前函数执行中的this
是fBound
的实例,说明是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实现原理相关推荐
- JavaScript内置一些方法的实现原理--new关键字,call/apply/bind方法--前戏
new关键字,call/apply/bind方法都和this的绑定有关,在学习之前,首先要理解this. 一起来学习一下this吧 首先.this是一个对象. 对象很好理解,引用类型值,可以实现如th ...
- 50行javaScript代码实现简单版的 call , apply ,bind 【中级前端面试基础必备】
在实现自己的call,apply,bind前,需要复习一下this. ###所谓的this其实可以理解成一根指针: 其实 this 的指向,始终坚持一个原理:this 永远指向最后调用它的那个对象,这 ...
- call(),apply(),bind()的用法及举例
通过学习call(),apply(),bind()的用法和区别,我们能更好的理解this及作用域的含义,为后面的编程打下基础. call()的用法: 调用一个函数,使其具有一个指定的this值和分别地 ...
- 复习javascript中call,apply,bind的用法
一直很难理解js中的call apply bind,在w3schools,mdn阅读了,也看了很多相关的文章,今天我来写下我理解的call apply bind 首先创建一个函数 function m ...
- call / apply / bind
对于 call / apply / bind 来说,他们的首要目的是用于改变执行上下文的 this 指针. call / apply 对 call / apply 的使用,一般都如下,用于改变执行环境 ...
- call() , apply() ,bind()的用法
call() , apply() ,bind()的用法 - 作用:改变this指向,可以传递参数 - 语法: A.call(B, 参数1, 参数2)A.apply(B, [ 参数1, 参数2])A.b ...
- JavaScript中的call,apply,bind学习总结
JavaScript 中的 call, apply, bind 这三个函数的作用和区别在各大论坛都被讨论了很多次了,但是我一直都还没来得及好好总结,这次正好看到了一个很不错的关于JavaScript ...
- JavaScript中call,apply,bind方法的总结。
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = {user:"追梦子",fn:fun ...
- call apply bind 的作用和区别
1.call apply bind 的作用和区别 作用: 都可以改变函数内部的this指向. 区别点: 1.call和apply会调用函数,并且改变函数内部this指向. 2.call和apply传递 ...
最新文章
- 一百年后,人类怎样编程?
- 2010 eWEEK 年度产品
- 15 错误边界与使用技巧
- 常用数据库的分页实现
- Java RandomAccessFile getFilePointer()方法与示例
- Flink - allowedLateness
- r语言pls分析_R语言:生存分析
- 为什么办理房产证要经过开发商和物业?
- 微信和QQ可以关闭广告了,每次能关6个月
- 智能优化算法:象群算法-附代码
- 引入网易云音乐播放器卡片
- Python 自动化测试 必会模块 Unittest
- D3.js中文版api-接口文档
- 【python】王者荣耀全英雄高清壁纸爬虫共467M(多线程)
- 记一次服务器被木马注入攻击
- AP系列文章——PDM麦克风
- 任正非霸气回应:没有谷歌,华为也能成为世界第一!
- hdu2097 Sky数
- python3个引号啥意思_Python中单引号,双引号,3个单引号及3个双引号的区别
- mysql查看密码_如何查看mysql数据库用户密码?