js面试,闭包等相关问题

js面试,闭包等相关问题

其实这一部分我不是太想说的,不过面向基础,而且面试也是喜欢问,我就根据我的理解说说吧!

在这里先说一下变量提升

改一改风格,先问几个问题
a.说一下this几种不同的使用场景
b.创建10个< a >标签,点击的时候弹出对应的序号,请手写代码
c.如何理解作用域
d.闭包你在项目开发中有用过吗?怎么使用的?
一、执行上下文

  • 范围:一段< script > 或者一个函数
  • 全局:变量定义、函数声明
  • 函数:变量定义、函数声明、this、argument(函数参数集合,类数组,值得注意的是es6箭头函数语法是没有这个东西的)

了解:函数声明和函数表达式的区别,其实没啥大的区别就是函数声明存在变量提升,而表达式不会

二、this
this这个东西,要在执行时才能确认,定义时无法确认,理解下面代码:

window.name = "window"
let a = {
	name:'A',
	fn:function(){
		console.log(this.name)
	}
}
a.fn() //这里this指向a
a.fn.call({name:'B'})  //这里this指向{name:"B"}
let fn1 = a.fn
fn1()   //这里this又是指向了window

上面代码 a.fn()打印结果是A,a.fn.call({name:‘B’})打印结果是B,最后一个打印结果是window
想必最后一个结果挺出乎意料的吧,为什么会这样呢?其实this的作用机制就是谁调用他this就指向谁
a.fn这个没什么好说的,很直白,就是a对象调用了fn,因此this指向了a
a.fn.call({name:‘B’}),这个call的作用就是改变了执行上下文,什么是执行上下文,前面已经列出来了,因此call将本来在a对象执行上下文,改换成了{name:‘B’}的执行上下文,因此就相当于{name:‘B’}.fn(),this指向调用他的{name:‘B’}
而let fn1 = a.fn 相当于

fn1 = function	(){
	console.log(this.name)
}

在浏览器中,所有的全局变量和函数其实可以认为是window上的属性和方法也就相当于

window.fn1 = function(){
	console.log(this.name)
}

因此是window调用了这个方法,this指向了window

扩展:this的使用场景
1.作为构造函数执行
2.作为对象属性执行
3.作为普通函数执行
4.call apply bind

三、作用域
a.js没有块级作用域,(es6有了let,我看了一本书好像把这个称为模拟块级作用域,是块级声明,这个感觉不用太纠结,哈哈哈)
b.js只有全局和函数作用域

四、闭包

//概念不多说
function F1(){
	var a = 100
	return function(){
		console.log(a)
	}
}
let f1 = F1()
var a = 200
let f1 = F1()
f1()

这条代码,let f1 = F1()其实就相当于
let f1 = function(){
console.log(a)
}
按通常情况,这个a会打印出全局a=200;但实际上由于它作为一个函数结果返回的,首先访问的是父级函数层的a,因此是100
闭包的使用场景:
a.函数作为返回值
b.函数作为参数传递

扩展:创建10个< a >标签,点击的时候弹出对应的序号,请手写代码

//这个就是上述的问题,es5中就需要用到闭包的特性
var i = null;
for(i = 0;i<10;i++){
	(function(i){
		var a = document.createElement('a');
		a.innerHTML = i + '
'; a.addEventListener('click',function(e){ e.preventDefault(); alert(i) }) document.body.appendChild(a) })(i) }

es6实现就方便多了,所以在项目中尽量使用let,const等es6语法

for(let i = 0;i<10;i++){
	let a = document.createElement('a');
	a.innerHTML = `${i}
`; a.addEventListener('click',(e)=>{ e.preventDefault(); alert(i) }) document.body.appendChild(a) }

你可能感兴趣的:(js面试,闭包等相关问题)