作用域链
- 作用域链:作用域链是ECMAScript引擎在执行代码时创建的,用来查找变量和函数的。
面试题
let a = 10;
funtion fn1(){
console.log(a);
let b=20;
fn2();
function fn2(){
console.log(b);
let c=30;
fn3();
function fn3(){
console.log(d);
var d=40;
console.log(c);
}
}
}
fn1();
if(true) {
let e = 1;
var f = 2;
console.log('e',e);
console.log('f',f);
}
console.log('e',e);
console.log('f',f);
- 对于作用域链我们直接通过创建态来定位作用域链条的某一环
- 手动取消链条甚至全局作用域,可以利用块级作用域做性能优化
this上下文 context
- this上下文:this上下文是函数执行时,this上下文指向的。
函数直接调用 -- this指向window
function fn1(){
console.log(this);
}
fn1();
隐式绑定 -- this指向调用堆栈的上一级
function fn2(){
console.log(this.a);
}
let obj = {
a:1,
fn2
}
obj.fn2();
面试题
const obj = {
a:1,
fn1: function(){
console.log(this.a);
console.log(this);
}
}
let fn2 = obj.fn1;
fn2();
const obj1 = {
a:1,
fn: function(){
return this.a;
}
}
const obj2 = {
a:2,
fn: function(){
return obj1.fn();
}
};
const obj3 = {
a:3,
fn: function(){
let fn = obj1.fn;
return fn();
}
}
console.log('obj1',obj1.fn());
console.log('obj2',obj2.fn());
console.log('obj3',obj3.fn());
- 在执行函数时,函数背上一级调用,删上下文指向上一级
- 直接变成公共函数时this指向window
将obj2.fn()结果指向obj2
obj2.fn.call(obj2);
const obj1 = {
a:1,
fn: function(){
return this.a;
}
}
const obj2 = {
a:2,
fn: obj1.fn
}
显式绑定(bind|call|apply)
function fn1(){
console.log(this);
}
fn1();
fn1.call({a:1});
fn1.apply({a:2});
fn1.bind({a:3})();
call、apply、bind区别
- call、apply、bind都是改变this指向,但是call、apply改变this指向后,函数执行完会返回函数本身,bind改变this指向后,函数执行完不会返回函数本身
- call、apply 传入参数不同,call多个参数一次传入,apply是传入数组
- 面试:手写apply & bind
Function.prototype.newBind = function() {
let self = this;
let args = Array.prototype.slice.call(arguments);
let newThis = args.shift();
function() {
return self.newBpply(newThis, args);
}
}
Function.prototype.newApply = function(context) {
if(typeof this !== 'function') {
throw new Error('type error');
}
context = context || window;
context.fn = this;
let result = arguments[1] ? context.fn(...arguments[1]) : context.fn();
delete context.fn;
return result;
}
new
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
test() {
console.log(this.name);
}
asynctest() {
setTimeout(() => {
console.log(this.name);
},100)
}
}
const person = new Person('zhangsan', 18);
person.test();
person.asynctest();
闭包 (如何突破作用域)
function test() {
let a = 1;
return function() {
console.log(a);
a++;
return a;
}
}
const fn = test();