待更

執(zhí)行上下文

js的每一行代碼javascript引擎都會創(chuàng)建執(zhí)行上下文( if/for等級塊沒有,需依附其他的作用域),每個執(zhí)行上下文都有三個屬性(變量對象,作用域鏈,this)但是也有不同:
全局:一個程序只有一個,默認(rèn)的執(zhí)行上下文,全局對象通常以this代之(綁定全局對象);
函數(shù):每個函數(shù)在調(diào)用的時候都會創(chuàng)建執(zhí)行上下文,一個程序可以有多個函數(shù)執(zhí)行上下文;
Eval:Eval比較特殊,單獨列出,不建議使用;
而執(zhí)行上下文一般都和執(zhí)行棧(調(diào)用棧)相關(guān)聯(lián),用于存儲程序所創(chuàng)建的執(zhí)行上下文,而引擎會執(zhí)行位于棧頂的執(zhí)行上下文,當(dāng)函數(shù)執(zhí)行完畢時,改函數(shù)的執(zhí)行上下文被彈出執(zhí)行棧而棧的數(shù)據(jù)存儲方式為先進(jìn)后出的規(guī)則。
考點:引出執(zhí)行棧,this指向(修改this方法),事件系統(tǒng)等

this指向

無指定情況下,this一般指全局對象,瀏覽器環(huán)境為window,node為global等,this的指向是由調(diào)用時決定的,而非創(chuàng)建時決定。
可通過apply、call、bind方法實現(xiàn)修改this,指向某個對象,都是Function原型鏈中Function.Prototype的屬性,具體用法如下:
apply:調(diào)用方法:Obj.apply(obj, [params]),使得Obj的執(zhí)行函數(shù)里的this指向obj,傳參方式是通過數(shù)組的形式,自執(zhí)行;
callObj.call(obj, arguments),和apply的區(qū)別在于第二個參數(shù)的類型,是類數(shù)組,自執(zhí)行;
bind:Obj.call(obj)(),創(chuàng)建一個新函數(shù),執(zhí)行時需手動調(diào)用,之后的參數(shù)根據(jù)原函數(shù)形參的個數(shù)決定,返回的函數(shù)可通過new調(diào)用;


以上三種方法適用于非箭頭函數(shù)或非嚴(yán)格模式下,前者this指向全局,后者普通函數(shù)沒有this,只有全局的,applycall傳入的objundefined時,會被替換成全局對象。

//  手寫call、apply、bind方法
Function.prototype._apply = function(ctx){
  const arg = arguments[1]; // 獲取數(shù)組形式的入?yún)?  const fn = Symbol(); // 保證屬性唯一性,通過Symbol創(chuàng)建
  let ctx = ctx || window;
  ctx[fn] = this;
  // 執(zhí)行函數(shù)
  if (arg) ctx.fn();
  else ctx.fn(...arg);
  delete ctx.fn; // 上下文中刪除函數(shù)引用
}
const Obj = {
  name: "bob",
  getName: function() {
    console.log(this.name)
  }
};
const obj = { name: "alice" };
Obj.getName();  // bob
Obj.getName._apply(obj); // alice
Function.prototype._bind = function(ctx) {
  if (typeof this !== 'function') throw new  TypeError (`${this} must be a function`)
  const self = this;
  const args = [].slice.call(arguments, []);
  const bind = function() {
    const parms = [].slice.call(arguments);
    return self.apply(ctx, args.concat(parms));
  }
  return bind;
}
const obj = { name: "alice" };
function test (a, b) {
  console.log(this.name);
  console.log(a, b);
}
const bind = test._bind(obj, 1);
bind(2); 
// alice 
// 1, 2

復(fù)雜實現(xiàn)方式
Function.prototype.bind2 = function (context) {
   if (typeof this !== "function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
    var fNOP = function () {};
    var fbound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        // 當(dāng)作為構(gòu)造函數(shù)時,this 指向?qū)嵗瑂elf 指向綁定函數(shù),因為下面一句 `fbound.prototype = this.prototype;`,已經(jīng)修改了 fbound.prototype 為 綁定函數(shù)的 prototype,此時結(jié)果為 true,當(dāng)結(jié)果為 true 的時候,this 指向?qū)嵗?        // 當(dāng)作為普通函數(shù)時,this 指向 window,self 指向綁定函數(shù),此時結(jié)果為 false,當(dāng)結(jié)果為 false 的時候,this 指向綁定的 context。
        self.apply(this instanceof self ? this : context, args.concat(bindArgs));
    }
    // 修改返回函數(shù)的 prototype 為綁定函數(shù)的 prototype,實例就可以繼承函數(shù)的原型中的值,但是直接修改 fbound.prototype 的時候,也會直接修改函數(shù)的 prototype,所以可以通過空函數(shù)作為一個中轉(zhuǎn)
   //  fbound.prototype = this.prototype;
    fNOP.prototype = this.prototype;
    fbound.prototype = new fNOP();
    return fbound;
}

模擬new的方式實現(xiàn)

function objectFactory() {
  var obj = object.create(null), Constructor = [].shift.call(arguments); 
  obj.__proto__ = Constructor.prototype;
  var ret = Constructor.apply(obj,arguments);
   return typeof ret ==='object '? ret : obj;
};

function Otaku(name, age) {
  this.name = name;
  this.age = age;
  this.habit ='Games';
}

Otaku.prototype.strength =60;
Otaku.prototype.sayYourName =function() {
  console.log('I am '+this.name);
}
var person = objectFactory(Otaku,'Kevin','18')
console.log(person.name)// Kevin
console.log(person.habit)// Games
console.log(person.strength)// 60
person.sayYourName();// I am Kevin
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容