Javascript的New、Apply、Bind、Call知多少

1 写在前面

Javascript中的多少apply、call、多少bind方法是多少前端代码开发中相当重要的概念,并且与this的多少指向密切相关。本篇文章我们将深入探讨这个关键词的多少作用,并尝试进行手动编写复现。多少

阅读文章前,多少我们带着几个问题进行研究:

用什么样的多少思路可以new关键字? apply、bind、多少call这三个方法有什么区别?多少 怎样手动实现一个apply、bind和call?多少

2 new关键词

new关键词的作用是执行一个构造函数,返回一个实例对象,多少根据构造函数的多少情况来确定是否可以接受参数的传递。

2.1 new的多少原理

使用new进行实例化对象,其步骤是多少:

创建一个新的空对象,即{ } 将该对象构造函数的作用域赋给新对象,this指向新对象(即将新对象作为this的上下文) 执行构造函数中的代码,云南idc服务商为这个新对象添加属性 如果该对象构造函数没有返回对象,则返回this function Person(){   this.name = "yichuan" } const p = new Person(); console.log(p.name);//"yichuan" 

我们可以看到当使用new进行实例化时,可以将构造函数的this指向新对象p。当不使用new时,此时构造函数的this指向window。

function Person(){   this.name = "yichuan" } const p = Person(); console.log(p);//undefined console.log(name);//"yichuan"   window.name console.log(p.name);//"yichuan" is undefined 

当我们在构造函数中直接返回一个和this无关的对象时,使用new关键字进行实例化对象,新生成的对象就是构造函数返回的对象,而非构造函数的this的对象。

function Person(){   this.name = "yichuan";   return { age:18}; } const p = new Person(); console.log(p);//{ age:18} console.log(p.name);//"undefined" console.log(p.age);/18 

此外,当构造函数返回的不是一个对象,而是基础数据类型的值时,使用new创建新对象,会将构造函数返回的值以对象形式给新对象。

function Person(){   this.name = "yichuan";   return "onechuan"; } const p = new Person(); console.log(p);//{ name:"yichuan"} console.log(p.name);//"yichuan" 

new关键词执行之后总是会返回一个对象,要么是实例,要么是return语句指定的服务器租用对象。

2.2 手写new的实现

new被调用后大致做了哪些事情?

让实例可以访问私有属性 让实例可以访问构造函数原型(constructor.prototype)所在原型链上的属性 构造函数返回的最后结果是引用数据类型 function new_object(ctor,...args){   //先要判断ctor是否为一个函数   if(typeof ctor !== "function"){     throw "ctor must be a function";   }   //创建一个空对象   const obj = new Object();   //将实例obj可以访问到ctor原型所在原型链的属性   obj.__proto__ = Object.create(ctor.prototype);   //将构造函数的this指向实例对象obj   const res = ctor.apply(obj,...args);   //确保最后new返回的是一个对象   const isObject = typeof res === "object" && typeof res!== null;   const isFunction = typeof res === "function";   return isObject || isFunction ? res : obj; } 

当然,我们还可以进行优化以下:

function new_object() {    // 1、获得构造函数,同时删除 arguments 中第一个参数   const ctor = [].shift.call(arguments);//其实这里是借用了数组的shift方法   // 2、创建一个空的对象并链接到原型,obj 可以访问构造函数原型中的属性   const obj = Object.create(ctor.prototype);   // 3、绑定 this 实现继承,obj 可以访问到构造函数中的属性   const ret =ctor.apply(obj, arguments);   // 4、优先返回构造函数返回的对象   return ret instanceof Object ? ret : obj; }; 

3 apply、bind以及call

apply、bind和call是挂载Function对象上的三个方法,调用这三个方法的必须是一个函数。

3.1 apply

apply() 方法调用一个具有给定 this 值的高防服务器函数,以及作为一个数组(或类似数组对象)提供的参数。apply()方法可以改变函数this的指向,且立即执行函数。

注意:Chrome 14 以及 Internet Explorer 9 仍然不接受类数组对象。如果传入类数组对象,它们会抛出异常。

func.apply(thisArg, [param1,param2,...]); 

在使用apply时,会将func的this指向改变为指向thisArg,然后以[param1,param2,...]参数数组作为参数输入。

func(["red","green","blue"]); func.apply(newFun, ["red","green","blue"]); 

我们可以看到都执行func时,第一个func函数的this指向的是window全局对象,而第二个func函数的this指向的是newFun。

Function.prototype.apply = function (context, arr) {      context = context ? Object(context) : window;      context.fn = this;     let result;    //判断有没有参数数组输入     if (!arr) {          result = context.fn();     } else {          result = context.fn(...arr);     }    //此处也可以使用eval进行处理    // const result = eval("context.fn(...arr)");     delete context.fn     return result; } 

3.2 bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

bind(thisArg,param1,param2,...); 

其实,bind的实现思路基本和apply一致,但是在最后实现返回结果时,bind不需要直接执行,而是以返回函数的形式返回结果,之后再通过执行这个结果即可。

先分析下bind的特性:首先是指定新对象this指向,再传入参数返回一个定义的函数,最后使用柯里化进行调用。同样的,我们也可以根据这些特性进行手动封装一个bind函数:

Function.prototype.bind = function(context){   //先要判断调用bind函数的是不是函数,需要抛出异常   if(typeof this !== "function"){     throw new Error("this bind function must be userd to function");   }   //存储this的指向   const self = this;   //context是新对象this指向的目标对象,而参数就是在第一个参数之后的参数   const args = Array.prototype.slice.call(arguments,1);   //创建一个空对象   const fun = function(){ }   //返回一个函数   const funBind = function(){     //返回所有的参数给bind函数     const bindArg = Array.prototype.slice.call(arguments);     //将传入的参数合并成一个新的参数数组,作为self.apply()的第二个参数     return self.apply(this instanceof fun ? this : context,  args.concat(bindArgs));     /
应用开发
上一篇:云上的创新为爱康搭建创新底座 让CT小车”开进了大山【2022戴尔科技峰会预告】
下一篇:如何利用可观测性技术优化数据中心的能源效率