执行上下文
js的每一行代码javascript引擎都会创建执行上下文( if/for等级块没有,需依附其他的作用域),每个执行上下文都有三个属性(变量对象,作用域链,this)但是也有不同:
全局:一个程序只有一个,默认的执行上下文,全局对象通常以this代之(绑定全局对象);
函数:每个函数在调用的时候都会创建执行上下文,一个程序可以有多个函数执行上下文;
Eval:Eval比较特殊,单独列出,不建议使用;
而执行上下文一般都和执行栈(调用栈)相关联,用于存储程序所创建的执行上下文,而引擎会执行位于栈顶的执行上下文,当函数执行完毕时,改函数的执行上下文被弹出执行栈而栈的数据存储方式为先进后出的规则。
考点:引出执行栈,this指向(修改this方法),事件系统等
this指向
无指定情况下,this一般指全局对象,浏览器环境为window
,node为global等,this的指向是由调用时决定的,而非创建时决定。
可通过apply
、call
、bind
方法实现修改this
,指向某个对象,都是Function
原型链中Function.Prototype
的属性,具体用法如下:
apply:调用方法:Obj.apply(obj, [params])
,使得Obj
的执行函数里的this
指向obj
,传参方式是通过数组的形式,自执行;
call:Obj.call(obj, arguments)
,和apply
的区别在于第二个参数的类型,是类数组,自执行;
bind:Obj.call(obj)()
,创建一个新函数,执行时需手动调用,之后的参数根据原函数形参的个数决定,返回的函数可通过new
调用;
以上三种方法适用于非箭头函数或非严格模式下,前者this
指向全局,后者普通函数没有this
,只有全局的,apply
和call
传入的obj
为undefined
时,会被替换成全局对象。
// 手写call、apply、bind方法
Function.prototype._apply = function(ctx){
const arg = arguments[1]; // 获取数组形式的入参
const fn = Symbol(); // 保证属性唯一性,通过Symbol创建
let ctx = ctx || window;
ctx[fn] = this;
// 执行函数
if (arg) ctx.fn();
else ctx.fn(...arg);
delete ctx.fn; // 上下文中删除函数引用
}
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
网友评论