目标
- 了解this在不同的环境、作用域下指代的是什么
- 了解闭包的作用、优缺点
- 了解js中各种作用域
知识要点
this
- (默认绑定)当函数自然执行的时候,this指向到window(严格模式下为undefined)
- (隐式绑定)当有对象调用函数时,函数中的this指向调用它的对象(a.b => b中this指向a)
- (显示绑定)通过call、apply、bind改变this的指向
- (new绑定)当执行new实例化时,this指向的是实例化出来的对象
- 箭头函数中,this指向到箭头函数所在作用域的上一层作用域中(箭头函数外部作用域)
作用域
- 全局作用域
- 函数作用域
- 块级作用域
作用域链:子函数可以使用父函数中的变量
function father(){
var a = 1;
function child(){
console.log(a);
}
}
变量提升、函数提升
- var有变量提升
- let也有变量提升,但是存在暂时性死区,在变量未初始化时不能使用
- 函数提升和变量提升的优先级(函数>变量),函数名和变量名同名是没有问题的
var a = 1;
function a() {
return 2;
}
console.log(a) // 1
变量、函数提升后 =>
function a() {
return 2;
}
var a;
a = 1;
console.log(a) // 1
闭包
什么是闭包?
闭包是内部函数持有外部函数的变量(导致外部函数中变量一直被内部函数持有,不会被gc)
闭包的优缺点?
优点:私有变量对外部调用方隐藏变量,在内存中维护一个变量
缺点:常驻内存,使用不当容易造成内存泄漏
补充知识点
如何实现一个call、apply、bind
Function.prototype.myCall = function() {
// 获取对象 》 对象中创建临时方法存放当前函数 》 执行对象中临时方法(重新定义this指向) 》 删除对象中临时方法
var args = Array.from(arguments);
var context = args.shift() || window;
context.fn = this;
var result = context.fn(...args);
delete context.fn;
return result;
}
Function.prototype.myApply = function() {
// 获取对象 》 对象中创建临时方法存放当前函数 》 执行对象中临时方法(重新定义this指向) 》 删除对象中临时方法
var args = Array.from(arguments);
var context = args.shift() || window;
context.fn = this;
var result = args.length > 0 ? context.fn(...args[0]): context.fn();
delete context.fn;
return result;
}
Function.prototype.myBind = function() {
// 获取老函数和对象 》 在return中使用老函数将函数中的this指向到对象中
if (typeof this !== 'function') new Error('type error');
var _this = this;
var args = Array.from(arguments);
var context = args.shift() || window;
return function() {
return _this.apply(context, args);
}
}
如何实现一个new
function createNew(Parent, ...params) {
// 定义一个空对象 》 空对象中prototype指向构造函数prototype 》 将this指向到对象 》 返回新创建的对象
var obj = Object.create({});
obj.__proto__ = Parent.prototype;
var result = Parent.apply(obj, params);
return typeof result === 'object' ? result : obj;
}