JS中bind,call,apply以及new的用法与实现

JS中bind,call,apply以及new的用法与实现

春招冲刺01.16日 - 01

1. 什么是bind,call,apply

  
bind,call,apply是JavaScript中Function对象自带的三个方法,用于改变函数体内部的 this 指向,也就是函数调用时的上下文(context)。

bind,call,apply三者都可以利用后续参数传参。其中bind不会立即调用,而是返回对应的绑定函数,其内的this指向为创建它时传入bind的 第一个参数,而传入bind的第二个及以后的参数作为 原函数的参数 来调用原函数。

bind(thisArg[, arg1[, arg2[, ...]]])

apply、call则是立即调用,改变的this指向他们的第一个参数,apply的第二个参数是一个参数数组,call的第二个及其以后的参数都是数组里面的元素。

call ( thisArg, arg1, arg2, ... )
apply ( thisArg ,[argArray] )

2. call的应用与实现

在call的语法call ( thisArg, arg1, arg2, ... )中,thisArg的传递情况有:

  • null,undefined或不传 此时指向window
  • 传递另一个函数B的函数名,函数中的this指向B的引用
  • 传递字符串、数值或布尔类型等基础类型,函数中的this指向其对应的包装对象,如 String、Number、Boolean
  • 传递一个对象,函数中的this指向这个对象

常用方法:

function pChain (){
this.name="pChainRoot";
this.nameprint=function(){
console.log('打印的名字是',this.name);
}
}

var newname={name:"PChainChild"};
var PChain=new pChain();
PChain.nameprint.call(newname); //PChainChild
PChain.nameprint(); //pChainRoot

模拟实现:

Function.prototype.myCall = function (thisArg,...args){

//thisArg为调用mycall方法的函数的this指向
var thisArg = thisArg || window

//将this赋给thisArg的fn属性
//此处this指代调用myCall的function
thisArg.fn = this;

var result = thisArg.fn(args);
delete thisArg.fn;
return result;

}
PChain.nameprint.myCall(newname); //pChainChild

3. apply的应用与实现

apply与call的作用是一样的,不过二者接收参数的方法不一样,apply要求将call的剩余参数存储在一个数组中。
当明确知道参数数量时用 call ,而不确定的时候用 apply,并将把参数 push 进数组传递进去,使函数内部也通过 arguments 这个数组来遍历所有的参数。
常用方法:

function pChain2 (name1,name2){
this.name1=name1;
this.name2=name2;
this.nameprint=function(){
console.log('打印的名字是',this.name1+'与'+this.name2);
}
}
function pChainChild2 (){
this.name1="PChainChild1";
this.name2="PChainChild2";
var PChain2 = new pChain2("pChainRoot1","pChainPoot2");

//call的传参方法
PChain2.nameprint.call(this,name1,name2); //PChainChild1与PChainChild2

PChain2.nameprint(); //pChainRoot1与pChainPoot2

//apply的传参方法
PChain2.nameprint.apply(this,[name1,name2]); //PChainChild1与PChainChild2
}

pChainChild2();

模拟实现:

Function.prototype.myApply = function(thisArg){
//thisArg为调用mycall方法的函数的this指向
var thisArg = thisArg || window

//将this赋给thisArg的fn属性
//此处this指代调用myCall的function
thisArg.fn = this;

var result;
if (arguments[1]) {
result = thisArg.fn(arguments[1]);
} else {
result = thisArg.fn();
}
delete thisArg.fn;
return result;
}

4. bind的应用与实现

bind是在es5中扩展的方法(IE6,7,8不支持),但是返回值是函数。

常用方法:

var bar= function () {
console.log(this.x);
}
var foo = {
x:3
}

bar(); //undefined

bar.bind (foo) (); //3

要注意的是多次 bind() 是无效的。

var foo2 = {
x:5
}
bar.bind (foo).bind (foo2) (); //3

模拟实现:

Function.prototype.myBind=function(){
var _this = this;
var context = [].shift.call(arguments);// 保存需要绑定的this上下文
var args = [].slice.call(arguments); //剩下参数转为数组

return function(){
_this.apply(context, [].concat.call(args, [].slice.call(arguments)));
}
}

5. new的应用与实现

在学习了原型与原型链 -> 12.29part2 之后,我们知道new在构建过程中,会发生的步骤为:

  • 生成新的对象
  • 新对象的__proto__属性指向构造函数的原型对象
  • 绑定this,将构造函数的作用域赋值给新对象
  • 返回新对象

因此手动模拟new关键字只需要实现上述四个步骤即可

function myNew(fn, ...args) {
const obj = {};

//绑定原型链
obj.proto = fn.prototype;

// 改变this指向
let result = fn.apply(obj, args)

// return result
// 确保new出来的是一个对象
return typeof result === "object" ? result : obj
}

posted @ 2021-01-19 14:34  凉将  阅读(419)  评论(0)    收藏  举报