成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開(kāi)發(fā) 前端
Javascript中的apply、call、bind方法是前端代碼開(kāi)發(fā)中相當(dāng)重要的概念,并且與this的指向密切相關(guān)。本篇文章我們將深入探討這個(gè)關(guān)鍵詞的作用,并嘗試進(jìn)行手動(dòng)編寫(xiě)復(fù)現(xiàn)。

[[438565]]

1 寫(xiě)在前面

Javascript中的apply、call、bind方法是前端代碼開(kāi)發(fā)中相當(dāng)重要的概念,并且與this的指向密切相關(guān)。本篇文章我們將深入探討這個(gè)關(guān)鍵詞的作用,并嘗試進(jìn)行手動(dòng)編寫(xiě)復(fù)現(xiàn)。

閱讀文章前,我們帶著幾個(gè)問(wèn)題進(jìn)行研究:

  • 用什么樣的思路可以new關(guān)鍵字?
  • apply、bind、call這三個(gè)方法有什么區(qū)別?
  • 怎樣手動(dòng)實(shí)現(xiàn)一個(gè)apply、bind和call?

2 new關(guān)鍵詞

new關(guān)鍵詞的作用是執(zhí)行一個(gè)構(gòu)造函數(shù),返回一個(gè)實(shí)例對(duì)象,根據(jù)構(gòu)造函數(shù)的情況來(lái)確定是否可以接受參數(shù)的傳遞。

2.1 new的原理

使用new進(jìn)行實(shí)例化對(duì)象,其步驟是:

  1. 創(chuàng)建一個(gè)新的空對(duì)象,即{}
  2. 將該對(duì)象構(gòu)造函數(shù)的作用域賦給新對(duì)象,this指向新對(duì)象(即將新對(duì)象作為this的上下文)
  3. 執(zhí)行構(gòu)造函數(shù)中的代碼,為這個(gè)新對(duì)象添加屬性
  4. 如果該對(duì)象構(gòu)造函數(shù)沒(méi)有返回對(duì)象,則返回this
  1. function Person(){ 
  2.  this.name = "yichuan" 
  3.  
  4. const p = new Person(); 
  5. console.log(p.name);//"yichuan" 

我們可以看到當(dāng)使用new進(jìn)行實(shí)例化時(shí),可以將構(gòu)造函數(shù)的this指向新對(duì)象p。當(dāng)不使用new時(shí),此時(shí)構(gòu)造函數(shù)的this指向window。

  1. function Person(){ 
  2.  this.name = "yichuan" 
  3.  
  4. const p = Person(); 
  5. console.log(p);//undefined 
  6. console.log(name);//"yichuan"   window.name 
  7. console.log(p.name);//"yichuan" is undefined 

當(dāng)我們?cè)跇?gòu)造函數(shù)中直接返回一個(gè)和this無(wú)關(guān)的對(duì)象時(shí),使用new關(guān)鍵字進(jìn)行實(shí)例化對(duì)象,新生成的對(duì)象就是構(gòu)造函數(shù)返回的對(duì)象,而非構(gòu)造函數(shù)的this的對(duì)象。

  1. function Person(){ 
  2.  this.name = "yichuan"
  3.   return {age:18}; 
  4.  
  5. const p = new Person(); 
  6. console.log(p);//{age:18} 
  7. console.log(p.name);//"undefined" 
  8. console.log(p.age);/18 

此外,當(dāng)構(gòu)造函數(shù)返回的不是一個(gè)對(duì)象,而是基礎(chǔ)數(shù)據(jù)類(lèi)型的值時(shí),使用new創(chuàng)建新對(duì)象,會(huì)將構(gòu)造函數(shù)返回的值以對(duì)象形式給新對(duì)象。

  1. function Person(){ 
  2.  this.name = "yichuan"
  3.   return "onechuan"
  4.  
  5. const p = new Person(); 
  6. console.log(p);//{name:"yichuan"
  7. console.log(p.name);//"yichuan" 

new關(guān)鍵詞執(zhí)行之后總是會(huì)返回一個(gè)對(duì)象,要么是實(shí)例,要么是return語(yǔ)句指定的對(duì)象。

2.2 手寫(xiě)new的實(shí)現(xiàn)

new被調(diào)用后大致做了哪些事情?

  1. 讓實(shí)例可以訪問(wèn)私有屬性
  2. 讓實(shí)例可以訪問(wèn)構(gòu)造函數(shù)原型(constructor.prototype)所在原型鏈上的屬性
  3. 構(gòu)造函數(shù)返回的最后結(jié)果是引用數(shù)據(jù)類(lèi)型
  1. function new_object(ctor,...args){ 
  2.  //先要判斷ctor是否為一個(gè)函數(shù) 
  3.   if(typeof ctor !== "function"){ 
  4.    throw "ctor must be a function"
  5.   } 
  6.   //創(chuàng)建一個(gè)空對(duì)象 
  7.   const obj = new Object(); 
  8.   //將實(shí)例obj可以訪問(wèn)到ctor原型所在原型鏈的屬性 
  9.   obj.__proto__ = Object.create(ctor.prototype); 
  10.   //將構(gòu)造函數(shù)的this指向?qū)嵗龑?duì)象obj 
  11.   const res = ctor.apply(obj,...args); 
  12.   //確保最后new返回的是一個(gè)對(duì)象 
  13.   const isObject = typeof res === "object" && typeof res!== null
  14.   const isFunction = typeof res === "function"
  15.   return isObject || isFunction ? res : obj; 

當(dāng)然,我們還可以進(jìn)行優(yōu)化以下:

  1. function new_object() { 
  2.   // 1、獲得構(gòu)造函數(shù),同時(shí)刪除 arguments 中第一個(gè)參數(shù) 
  3.   const ctor = [].shift.call(arguments);//其實(shí)這里是借用了數(shù)組的shift方法 
  4.   // 2、創(chuàng)建一個(gè)空的對(duì)象并鏈接到原型,obj 可以訪問(wèn)構(gòu)造函數(shù)原型中的屬性 
  5.   const obj = Object.create(ctor.prototype); 
  6.   // 3、綁定 this 實(shí)現(xiàn)繼承,obj 可以訪問(wèn)到構(gòu)造函數(shù)中的屬性 
  7.   const ret =ctor.apply(obj, arguments); 
  8.   // 4、優(yōu)先返回構(gòu)造函數(shù)返回的對(duì)象 
  9.   return ret instanceof Object ? ret : obj; 
  10. }; 

3 apply、bind以及call

apply、bind和call是掛載Function對(duì)象上的三個(gè)方法,調(diào)用這三個(gè)方法的必須是一個(gè)函數(shù)。

3.1 apply

apply() 方法調(diào)用一個(gè)具有給定 this 值的函數(shù),以及作為一個(gè)數(shù)組(或類(lèi)似數(shù)組對(duì)象)提供的參數(shù)。apply()方法可以改變函數(shù)this的指向,且立即執(zhí)行函數(shù)。

注意:Chrome 14 以及 Internet Explorer 9 仍然不接受類(lèi)數(shù)組對(duì)象。如果傳入類(lèi)數(shù)組對(duì)象,它們會(huì)拋出異常。

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

在使用apply時(shí),會(huì)將func的this指向改變?yōu)橹赶騮hisArg,然后以[param1,param2,...]參數(shù)數(shù)組作為參數(shù)輸入。

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

我們可以看到都執(zhí)行func時(shí),第一個(gè)func函數(shù)的this指向的是window全局對(duì)象,而第二個(gè)func函數(shù)的this指向的是newFun。

  1. Function.prototype.apply = function (context, arr) { 
  2.     context = context ? Object(context) : window;  
  3.     context.fn = this; 
  4.    
  5.     let result; 
  6.    //判斷有沒(méi)有參數(shù)數(shù)組輸入 
  7.     if (!arr) { 
  8.         result = context.fn(); 
  9.     } else { 
  10.         result = context.fn(...arr); 
  11.     } 
  12.    //此處也可以使用eval進(jìn)行處理 
  13.    // const result = eval("context.fn(...arr)"); 
  14.        
  15.     delete context.fn 
  16.     return result; 

3.2 bind

bind() 方法創(chuàng)建一個(gè)新的函數(shù),在 bind() 被調(diào)用時(shí),這個(gè)新函數(shù)的 this 被指定為 bind() 的第一個(gè)參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調(diào)用時(shí)使用。

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

其實(shí),bind的實(shí)現(xiàn)思路基本和apply一致,但是在最后實(shí)現(xiàn)返回結(jié)果時(shí),bind不需要直接執(zhí)行,而是以返回函數(shù)的形式返回結(jié)果,之后再通過(guò)執(zhí)行這個(gè)結(jié)果即可。

先分析下bind的特性:首先是指定新對(duì)象this指向,再傳入?yún)?shù)返回一個(gè)定義的函數(shù),最后使用柯里化進(jìn)行調(diào)用。同樣的,我們也可以根據(jù)這些特性進(jìn)行手動(dòng)封裝一個(gè)bind函數(shù):

  1. Function.prototype.bind = function(context){ 
  2.  //先要判斷調(diào)用bind函數(shù)的是不是函數(shù),需要拋出異常 
  3.   if(typeof this !== "function"){ 
  4.    throw new Error("this bind function must be userd to function"); 
  5.   } 
  6.   //存儲(chǔ)this的指向 
  7.   const self = this; 
  8.   //context是新對(duì)象this指向的目標(biāo)對(duì)象,而參數(shù)就是在第一個(gè)參數(shù)之后的參數(shù) 
  9.   const args = Array.prototype.slice.call(arguments,1); 
  10.    
  11.   //創(chuàng)建一個(gè)空對(duì)象 
  12.   const fun = function(){} 
  13.    
  14.   //返回一個(gè)函數(shù) 
  15.   const funBind = function(){ 
  16.    //返回所有的參數(shù)給bind函數(shù) 
  17.     const bindArg = Array.prototype.slice.call(arguments); 
  18.     //將傳入的參數(shù)合并成一個(gè)新的參數(shù)數(shù)組,作為self.apply()的第二個(gè)參數(shù) 
  19.     return self.apply(this instanceof fun ? this : context,  args.concat(bindArgs)); 
  20.     /**********************說(shuō)明************************************/ 
  21.   } 
  22.    
  23.   //空對(duì)象的原型指向綁定函數(shù)的原型 
  24.   fun.prototype = this.prototype; 
  25.   //空對(duì)象的實(shí)例賦值給 funBind.prototype 
  26.   funBind.prototype = new fun(); 
  27.   return funBinf; 

補(bǔ)充說(shuō)明:

  • this instanceof fun返回為true時(shí),表示的是fun是一個(gè)構(gòu)造函數(shù),其this指向?qū)嵗苯訉ontext作為參數(shù)輸入
  • this instanceof fun返回為false時(shí),表示的是fun是一個(gè)普通函數(shù),其this指向頂級(jí)對(duì)象window,將綁定函數(shù)的this指向context對(duì)象

當(dāng)然,我們也可以寫(xiě)成這種形式:

  1. Function.prototype.bind = function(context,...args){ 
  2.  //先要判斷調(diào)用bind函數(shù)的是不是函數(shù),需要拋出異常 
  3.   if(typeof this !== "function"){ 
  4.    throw new Error("this bind function must be userd to function"); 
  5.   } 
  6.   //存儲(chǔ)this的指向 
  7.   const self = this; 
  8.    
  9.   const fBind = function(){ 
  10.    self.apply(this instanceof self ? this: context, args.concat(Array.prototype.slice.call(arguments)));  
  11.   } 
  12.   if(this.prototype){ 
  13.    fBind.prototype = Object.create(this.prototype); 
  14.   } 
  15.   return fBind; 

注意:Object.create()是es2015語(yǔ)法引入的新特性,因此在IE<9的瀏覽器是不支持的。

3.3 call

call() 方法使用一個(gè)指定的 this 值和單獨(dú)給出的一個(gè)或多個(gè)參數(shù)來(lái)調(diào)用一個(gè)函數(shù)。使用調(diào)用者提供的 this 值和參數(shù)調(diào)用該函數(shù)的返回值。若該方法沒(méi)有返回值,則返回 undefined。

  1. function.call(thisArg, param1, param2, ...) 

注意:該方法的語(yǔ)法和作用與 apply() 方法類(lèi)似,只有一個(gè)區(qū)別,就是 call() 方法接受的是一個(gè)參數(shù)列表,而 apply() 方法接受的是一個(gè)包含多個(gè)參數(shù)的數(shù)組。

call函數(shù)的實(shí)現(xiàn):

  1. Function.prototype.call = function(context,...args){ 
  2.   //將函數(shù)設(shè)置為對(duì)象的屬性 
  3.  context = context || window; 
  4.   context.fn = this; 
  5.    
  6.   //執(zhí)行函數(shù) 
  7.   const result = eval("context.fn(...args)"); 
  8.   //刪除對(duì)象的這個(gè)屬性 
  9.   delete context.fn; 
  10.   return result; 

4 參考文章

  • 《解析 bind 原理,并手寫(xiě) bind 實(shí)現(xiàn)》
  • 《解析 call/apply 原理,并手寫(xiě) call/apply 實(shí)現(xiàn)》
  • 《Javascript核心原理精講》

5 寫(xiě)在最后

在這篇文章中,我們知道apply、bind、call的區(qū)別在于:

  • apply、call改變了this指向后,會(huì)立即進(jìn)行調(diào)用函數(shù),返回的是執(zhí)行結(jié)果
  • bind在改變this指向后,返回的是一個(gè)函數(shù),需要另外再進(jìn)行調(diào)用一次
  • bind、call傳遞的第一個(gè)參數(shù)都是this將要指向的對(duì)象,后面都是一個(gè)一個(gè)參數(shù)的形式輸入
  • apply傳遞的第一個(gè)參數(shù)也是this將要指向的對(duì)象,后面?zhèn)鬟f的第二個(gè)參數(shù)是一個(gè)參數(shù)數(shù)組

 

責(zé)任編輯:姜華 來(lái)源: 前端萬(wàn)有引力
相關(guān)推薦

2021-06-18 07:16:17

JavaScript apply()方法call()方法

2024-03-15 08:21:17

bindJavaScrip函數(shù)

2024-08-26 14:35:19

JavaScript關(guān)鍵字對(duì)象

2017-10-10 14:36:07

前端Javascriptapply、call、

2015-03-02 09:22:09

Javascript函數(shù)用法apply

2024-08-26 08:36:26

2024-08-20 16:04:27

JavaScript開(kāi)發(fā)

2021-12-04 11:17:32

Javascript繼承編程

2011-03-22 09:49:15

JavaScript

2021-12-10 07:47:30

Javascript異步編程

2021-06-09 07:01:30

前端CallApply

2021-11-30 06:56:58

CallApply函數(shù)

2021-12-11 18:59:35

JavascriptJSON應(yīng)用

2021-12-03 15:24:45

Javascript數(shù)據(jù)類(lèi)型

2021-12-07 08:01:33

Javascript 垃圾回收機(jī)制前端

2021-12-06 07:15:48

Javascript作用域閉包

2012-02-13 22:50:59

集群高可用

2024-08-06 10:07:15

2022-05-08 18:02:11

tunnel隧道云原生

2017-07-14 10:51:37

性能優(yōu)化SQL性能分析
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 古装三级在线播放 | 国产精品视频yy9299一区 | 久久网日本 | 国产精品美女久久久久久免费 | 特黄毛片视频 | 亚洲一区二区精品视频 | 一区二区亚洲 | 91在线视频免费观看 | 日本一区不卡 | 成人午夜免费视频 | 狠狠久久综合 | 在线亚洲一区二区 | 欧美亚洲激情 | 91精品亚洲 | 男人天堂av网 | 一级毛片视频在线 | 日韩免费视频 | 国产成人99久久亚洲综合精品 | 国产精品久久久久久久久图文区 | 免费久久久 | 在线午夜电影 | 国产欧美在线 | 亚洲 欧美 另类 综合 偷拍 | 国产精品久久久久久久免费大片 | 国产免费国产 | 国产精品久久国产精品久久 | 我要看黄色录像一级片 | 91香蕉嫩草 | 欧美成人第一页 | 国产精品视频网 | 欧美亚洲国语精品一区二区 | 亚洲午夜网 | 国产精品123区 | 日韩成人精品 | 精品国产一区二区三区性色 | 国产视频福利 | 成年人网站免费视频 | 成人亚洲一区 | 伊人精品在线 | 人人爽日日躁夜夜躁尤物 | 91久久综合亚洲鲁鲁五月天 |