Function.prototype.call()
==call()== 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数。 该方法和apply()类似,区别在于,==call()可以接收若干参数==,而==apply()接收的是一个包含多个参数的数组==。
用call可以继承
- 通过父类的构造函数 ==call== 方法可以实现继承。
例子如下:
function Person(name,age){
this.name = name ;
this.age = age;
}
function Man(name,age,sex){
Person.call(this,name,age)
this.sex= sex;
}
let abc = new Man('abc',18,'男');
console.log(abc);
解释 : abc实例都会拥有 Person 类 的name,age变量。
- 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);
}
- call方法指定上下文的this
let person = {
age:18,
name:'abc'
}
function greet(){
console.log(this.age,this.name,this)
//18 "abc" {age: 18, name: "abc"}
}
greet.call(person);
call 原理代码实现如下
/*
1、this 参数可以传 null 或者 undefined,此时 this 指向 window
2、this 参数可以传基本类型数据,原生的 call 会自动用 Object() 转换
3、函数是可以有返回值的
*/
Function.prototype.myCall = function(context){
context = context ? Object(context) : window;
//对传入的对象 添加一个fn属性 并且fn=this this即当前函数;
context.fn = this;
//截取当前 arguments 参数从第二个到最后一个,
//因为第一个参数是需要绑定的目标对象
let args = [...arguments].slice(1);
//执行函数 传入参数;
let result = context.fn(...args);
delete context.fn;//删除创建了属性
return result //返回函数的返回值 没有即undefined
}
Function.prototype.apply()
apply( ):两个参数,第一个是运行函数的作用域,第二个是参数数组(可以是array的实例,或者arguments对象)。 call( ):参数个数不定,第一个是运行函数的作用域,其余传递给函数的参数逐个列出。 apply()和 call()的2个作用:给函数传参、扩充作用域; 至于是使用 apply( )还是 call( ),完全取决于你采取哪种给函数传递参数的方式最方便
实现原理
Function.prototype.myapply=function(context,arr){
context = context ? Object(context) : window;
context.fn = this;
let result;
if(!arr){
result = context.fn();
}else{
result = context.fn(...arr);
}
delete context.fn;
return rexult;
}
Function.prototype.bind()
==bind==方法==创建一个新函数==, 在调用时设置this关键字为提供的值。 并在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项。 语法: function.bind(thisArg, [arg1[, arg2[, ...]]])
举个例子
let obj = {
name: 'joker'
}
function fn() {
console.log(this.name)
}
let bindFn = fn.bind(obj)
bindFn()
// joker
从上面例子可以看出
- bind可以绑定 ==this== 到传入的对象
- bind方法返回一个函数
那么我们使用(高阶函数)实现一个简易的bind方法
Function.prototype.bind = function(context) {
let _me = this
return function() {
return _me.apply(context)
}
}
上面方法的缺陷 :无法解决 fn 方法的传参问题;
再举个例子 2 :如下
bind可以多次传参
let obj ={a:1};
function fn(name,age){
console.log(name,age,this);
}
let bindFn = fn.bind(obj,'abc');
bindFn(18) //abc 18 {a: 1}
上面例子解释:
- fn函数调用bind方法 将fn函数内部的this指到obj上,并且传入参数 ‘abc’,bind方法返回的一个新创建的函数保存到 bindFn变量 上;
- 执行 bindFn 是又传入了一个参数 18。
- 以上操作 相当于 将fn函数内部的this指到obj上,并且给fn函数传参 name=‘abc’ , age = 18;
==因此之前的函数需要改一改==
Function.prototype.bind = function(context){
let self = this;
//获取bind方法传入的参数,截取第二个到末尾;
let bindArgs = [...arguments].slice(1);
return function(){
//获取函数执行传入的参数
let fnArgs = [...arguments].slice();
return self.apply(context,bindArgs.concat(fnArgs))
}
}