京东前端常考面试题(附答案)
前端进阶面试题详细解答
实现一个三角形
CSS绘制三角形主要用到的是border属性,也就是边框。
平时在给盒子设置边框时,往往都设置很窄,就可能误以为边框是由矩形组成的。实际上,border属性是右三角形组成的,下面看一个例子:
div {width: 0;height: 0;border: 100px solid;border-color: orange blue red green;
}
将元素的长宽都设置为0
(1)三角1
div { width: 0; height: 0; border-top: 50px solid red; border-right: 50px solid transparent; border-left: 50px solid transparent;}
(2)三角2
div {width: 0;height: 0;border-bottom: 50px solid red;border-right: 50px solid transparent;border-left: 50px solid transparent;
}
(3)三角3
div {width: 0;height: 0;border-left: 50px solid red;border-top: 50px solid transparent;border-bottom: 50px solid transparent;
}
(4)三角4
div {width: 0;height: 0;border-right: 50px solid red;border-top: 50px solid transparent;border-bottom: 50px solid transparent;
}
(5)三角5
div {width: 0;height: 0;border-top: 100px solid red;border-right: 100px solid transparent;
}
还有很多,就不一一实现了,总体的原则就是通过上下左右边框来控制三角形的方向,用边框的宽度比来控制三角形的角度。
display的block、inline和inline-block的区别
(1)block: 会独占一行,多个元素会另起一行,可以设置width、height、margin和padding属性;
(2)inline: 元素不会独占一行,设置width、height属性无效。但可以设置水平方向的margin和padding属性,不能设置垂直方向的padding和margin;
(3)inline-block: 将对象设置为inline对象,但对象的内容作为block对象呈现,之后的内联对象会被排列在同一行内。
对于行内元素和块级元素,其特点如下:
(1)行内元素
- 设置宽高无效;
- 可以设置水平方向的margin和padding属性,不能设置垂直方向的padding和margin;
- 不会自动换行;
(2)块级元素
- 可以设置宽高;
- 设置margin和padding都有效;
- 可以自动换行;
- 多个块状,默认排列从上到下。
JS闭包,你了解多少?
应该有面试官问过你:
- 什么是闭包?
- 闭包有哪些实际运用场景?
- 闭包是如何产生的?
- 闭包产生的变量如何被回收?
这些问题其实都可以被看作是同一个问题,那就是面试官在问你:你对JS闭包了解多少?
来总结一下我听到过的答案,尽量完全复原候选人面试的时候说的原话。
答案1: 就是一个function里面return了一个子函数,子函数访问了外面那个函数的变量。
答案2: for循环里面可以用闭包来解决问题。
for(var i = 0; i < 10; i++){setTimeout(()=>console.log(i),0)
}
// 控制台输出10遍10.
for(var i = 0; i < 10; i++){(function(a){setTimeout(()=>console.log(a),0)})(i)
}// 控制台输出0-9
答案3: 当前作用域产产生了对父作用域的引用。
答案4: 不知道。是跟浏览器的垃圾回收机制有关吗?
开杠了。请问,小伙伴的答案和以上的内容有多少相似程度?
其实,拿着这些问题好好想想,你就会发现这些问题都只是为了最终那一个问题。
闭包的底层实现原理
1. JS执行上下文
我们都知道,我们手写的js代码是要经过浏览器V8进行预编译后才能真正的被执行。例如变量提升、函数提升。举个栗子。
// 栗子:
var d = 'abc';
function a(){console.log("函数a");
};
console.log(a); // ƒ a(){ console.log("函数a"); }
a(); // '函数a'
var a = "变量a";
console.log(a); // '变量a'
a(); // a is not a function
var c = 123;// 输出结果及顺序:
// ƒ a(){ console.log("函数a"); }
// '函数a'
// '变量a'
// a is not a function// 栗子预编后相当于:
function a(){console.log("函数a");
};
var d;
console.log(a); // ƒ a(){ console.log("函数a"); }
a(); // '函数a'a = "变量a"; // 此时变量a赋值,函数声明被覆盖console.log(a); // "变量a"
a(); // a is not a function
那么问题来了。 请问是谁来执行预编译操作的?那这个谁又是在哪里进行预编译的?
是的,你的疑惑没有错。js代码运行需要一个运行环境,那这个环境就是执行上下文。 是的,js运行前的预编译也是在这个环境中进行。
js执行上下文分三种:
全局执行上下文: 代码开始执行时首先进入的环境。函数执行上下文:函数调用时,会开始执行函数中的代码。eval执行上下文:不建议使用,可忽略。
那么,执行上下文的周期,分为两个阶段:
创建阶段- 创建词法环境
- 生成变量对象(
VO),建立作用域链、作用域链、作用域链(重要的事说三遍) - 确认
this指向,并绑定this
执行阶段。这个阶段进行变量赋值,函数引用及执行代码。
你现在猜猜看,预编译是发生在什么时候?
噢,我忘记说了,其实与编译还有另一个称呼:执行期上下文。
预编译发生在函数执行之前。预编译四部曲为:
- 创建
AO对象 - 找形参和变量声明,将变量和形参作为AO属性名,值为
undefined - 将实参和形参相统一
- 在函数体里找到函数声明,值赋予函数体。最后程序输出变量值的时候,就是从
AO对象中拿。
所以,预编译真正的结果是:
var AO = {a = function a(){console.log("函数a");};d = 'abc'
}
我们重新来。
1. 什么叫变量对象?
变量对象是 js 代码在进入执行上下文时,js 引擎在内存中建立的一个对象,用来存放当前执行环境中的变量。
2. 变量对象(VO)的创建过程
变量对象的创建,是在执行上下文创建阶段,依次经过以下三个过程:
-
创建
arguments对象。对于函数执行环境,首先查询是否有传入的实参,如果有,则会将参数名是实参值组成的键值对放入
arguments对象中。否则,将参数名和undefined组成的键值对放入arguments对象中。
//举个栗子
function bar(a, b, c) {console.log(arguments); // [1, 2]console.log(arguments[2]); // undefined
}
bar(1,2)
- 当遇到同名的函数时,后面的会覆盖前面的。
console.log(a); // function a() {console.log('Is a ?') }
function a() {console.log('Is a');
}
function a() {console.log('Is a ?')
}/**ps: 在执行第一行代码之前,函数声明已经创建完成.后面的对之前的声明进行了覆盖。**/
- 检查当前环境中的变量声明并赋值为
undefined。当遇到同名的函数声明,为了避免函数被赋值为undefined,会忽略此声明
console.log(a); // function a() {console.log('Is a ?') }
console.log(b); // undefined
function a() {console.log('Is a ');
}
function a() {
console.log('Is a ?');
}
var b = 'Is b';
var a = 10086;/**这段代码执行一下,你会发现 a 打印结果仍旧是一个函数,而 b 则是 undefined。**/
根据以上三个步骤,对于变量提升也就知道是怎么回事了。
3. 变量对象变为活动对象
执行上下文的第二个阶段,称为执行阶段,在此时,会进行变量赋值,函数引用并执行其他代码,此时,变量对象变为活动对象。
我们还是举上面的例子:
console.log(a); // function a() {console.log('fjds
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
