this指针/闭包/作用域

作用域和上下文、闭包

作用域

在特定场景下、特定范围内,查找变量的一套规则。一般情况下特指:静态作用域、词法作用域,即代码层面上的。
从作用范围分类:

  1. 全局作用域
  2. 函数作用域:在函数内声明的所有变量,在函数体内是始终可见的,可以在整个函数范围内复用。
  3. 块作用域:是一个用来对之前的最小授权原则进行扩展的工具,将代码在函数中隐藏信息扩展为在块中。
    什么会构成块级作用域:if、for、{…}。
    当let作为块级作用域时,会存在暂时性死区。
    暂时性死区的范围:从let声明的变量的块的第一行,到声明变量之间的这个区域,被称为暂时性死区。暂时性死区存在时,会让let绑定这个区域,在这个区域内,无法执行该变量的其他声明。
函数表达式

代码的预编译阶段:

  1. 对变量的内存空间进行分配;
  2. 对变量声明进行提升,但是值为undefined;
  3. 对所有非表达式的声明进行提升。
执行上下文

执行上下文:
作用域关注的函数生命在何处,而上下文主要关注的是函数从何处开始调用。

闭包

定义:函数嵌套函数时,内层函数引用了外层函数作用域下的变量,并且内层函数在全局环境下可访问,这样便形成了闭包。(简单理解:当函数的执行上下文没有在原本的词法作用域内,就形成了闭包)。
闭包常见的场景:函数式编程、window-event handler、setTimeout。

this

this的使用规则

this的指向:this的指向是根据执行上下文动态决定的。

  1. 在简单调用时,this默认指向的是window、global、undefined,分别对应浏览器端、node端、严格模式
  2. 对象调用时,绑定在对象上
  3. 使用call/apply/bind时,绑定在指定的参数上
  4. 使用new关键字,通过构造函数调用创建对象上
  5. 以上2、3、4优先级:new>call/apply/bind>对象调用
  6. 使用箭头函数时,根据外层的规则决定this的指向。
this例题分析
var number = 5;//5-10-20
var obj = {
	number: 3,
	//fn1是立即执行函数,在JS解析时会执行
	fn1: (function() {
		var number;//持久化变量-3-9-27
		this.number *= 2;//全局定义的number会变成10
		number = number * 2;
		number = 3;//此处赋值为3,上述number*2可不管
		return function() {
			var num = this.number;
			this.number *= 2;//使全局的number变为20
			console.log(num);//【10】——【3】
			number *= 3;//3*3=9,9*3=27
			console.log(number);//【9】——【27】
		}
	})();
}
var fn1 = obj.fn1;//无console
fn1.call(null); // fn1();//【10】【9】
obj.fn1();//【3】【27】
console.log(window.number);//【20】
// 10, 9, 3, 27 ,20
什么时候需要考虑this的指向问题?
  1. 函数式编程
  2. 闭包
bind的实现
  1. 在不考虑new的优先级
Function.prototype.bind = Function.prototype.bind || function(context) {
	const fn = this;
	const args = Array.prototype.slice.call(arguments, 1);
	return function(...innerArgs) {
		const allArgs = [...args, ...innerArgs];
		return fn.apply(context, allArgs);
	}	
}
//test
function foo() {
    this.baz = "bar";
    return this.baz;
}
var func = foo.bind({baz:"baz"});
func() // "baz";
new func(); // baz: bar
  1. 考虑new的优先级:bind 返回的函数如果作为构造函数搭配 new 关键字出现的话,这种绑定就需要被忽略,this要绑定在实例上,也就是说,new 操作符要高于bind 绑定
Function.prototype.bind = Function.prototype.bind || function(context) {
	const fn = this;
	const args = Array.prototype.slice.call(arguments, 1);
	var F = function() {};
	F.prototype = this.prototype;
	var bound = function() {
		var innerArgs = Array.prototype.slice.call(arguments);
		const allArgs = [...args, ...innerArgs];
		// 如果存在new, 绑定的对象不一样
		return fn.apply(this instanceof F ? this : context || this, allArgs);
	}
	bound.prototype = new F();
	return bound;
}
//但没有修复length属性
  1. 终版:满足标准的 es5-shim
function bind(that) {
    var target = this;
    if (!isCallable(target)) {
        throw new TypeError('Function.prototype.bind called on incompatible ' + target);
    }
    var args = array_slice.call(arguments, 1);
    var bound;
    var binder = function () {
        if (this instanceof bound) {
            var result = target.apply(
                this,
                array_concat.call(args, array_slice.call(arguments))
            );
            if ($Object(result) === result) {
                return result;
            }
            return this;
        } else {
            return target.apply(
                that,
                array_concat.call(args, array_slice.call(arguments))
            );
        }
    };
    var boundLength = max(0, target.length - args.length);
    var boundArgs = [];
    for (var i = 0; i < boundLength; i++) {
        array_push.call(boundArgs, '$' + i);
    }
    bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder);

    if (target.prototype) {
        Empty.prototype = target.prototype;
        bound.prototype = new Empty();
        Empty.prototype = null;
    }
    return bound;
}
实现一个call函数
function called(context) {
	const args = Array.prototype.slice.call(arguments, 1);
	//
	context.fn = this;
	if(context) {
		const result = context.fn(...args);
		delete context.fn;
		return result;
	}else {
		return this(...args);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值