一.有一个类以下:html
functionPerson(name) {
this.name = name
}
let p = new Person('Tom');
复制代码
p.__proto__
等于什么?答案: Person.prototype前端
Person.__proto
等于什么?答案: Function.prototypereact
解析:es6
1,2两问其实问的是同一个问题,都是考察原型链相关的知识,咱们只须要记住一句话就能够迎刃而解。实例的__proto__属性(原型)等于其构造函数的prototype属性。实例p的构造函数为Person,而Person的构造函数为Function,结果就一目了然了。面试
举一反三数组
var foo = {},
F = function(){};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b';
console.log(foo.a)
console.log(foo.b)
console.log(F.a)
console.log(F.b)
复制代码
这里就不给答案了,你们本身分析一下,而后再去控制台运行一下吧!冬天到了,动动手,暖一暖,有木有以为笔者仍是至关的贴心的!!!服务器
若将题干改成react-router
functionPerson(name) { this.name = name return name; } let p = new Person('Tom');闭包
实例化Person过程当中,Person返回什么(或者p等于什么)?socket
答案:
{name: 'Tom'}
复制代码
若将题干改成
functionPerson(name) { this.name = name return {} } let p = new Person('Tom');
实例化Person过程当中,Person返回什么(或者p等于什么)?
答案:
{}
复制代码
解析
构造函数不须要显示的返回值。使用new来建立对象(调用构造函数)时,若是return的是非对象(数字、字符串、布尔类型等)会忽而略返回值;若是return的是对象,则返回该对象(注:若return null也会忽略返回值)。
答案:
在 JavaScript 中,判断一个变量的类型尝尝会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,不管引用的是什么类型的对象,它都返回 “object”。
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。 语法:object instanceof constructor 参数:object(要检测的对象.)constructor(某个构造函数) 描述:instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
答案是我整理后的,可能以为我回答的并不许确,面试官又举了一个例子给我。
若是Student inherit from Person(Student类继承Person,需是基于原型的继承),let s = new Student('Lily'),那么s instanceof Person返回什么?
functionPerson (name) { this.name = name; }
functionStudent () {
}
Student.prototype = Person.prototype; Student.prototype.constructor = Student;
let s = new Student('Tom'); console.log(s instanceof Person); // 返回 true
答案: true
答案
- 建立一个新对象,同时继承对象类的原型,即Person.prototype;
- 执行对象类的构造函数,同时该实例的属性和方法被this所引用,即this指向新构造的实例;
- 若是构造函数return了一个新的“对象”,那么这个对象就会取代整个new出来的结果。若是构造函数没有return对象,那么就会返回步骤1所建立的对象,即隐式返回this。(通常状况下构造函数不会返回任何值,不过在一些特殊状况下,若是用户想覆盖这个值,能够选择返回一个普通的对象来覆盖。)
用代码来阐述
// let p = new Person()let p = (function () {
let obj = {};
obj.__proto__ = Person.prototype;
// 其余赋值语句...return obj;
})();
复制代码
下面经过代码阐述instanceof的内部机制,假设如今有 x instanceof y 一条语句,则其内部实际作了以下判断:
while(x.__proto__!==null) {
if(x.__proto__===y.prototype) {
returntrue;
break;
}
x.__proto__ = x.__proto__.proto__;
}
if(x.__proto__==null) {returnfalse;}
复制代码
x会一直沿着隐式原型链__proto__向上查找直到x.__proto__.__proto__......===y.prototype
为止,若是找到则返回true,也就是x为y的一个实例。不然返回false,x不是y的实例。
举一反三
functionF() {}
functionO() {}
O.prototype = new F();
var obj = new O();
console.log(obj instanceof O); // trueconsole.log(obj instanceof F); // trueconsole.log(obj.__proto__ === O.prototype); // trueconsole.log(obj.__proto__.__proto__ === F.prototype); // true
复制代码
根据new 的内部机制改写上面代码
functionF() {}
functionO() {}
var obj = (function () {
var obj1 = {};
obj1.__proto__ = F.prototype; // new F();
O.prototype = obj1; // O.prototype = new F();
obj.__proto__ = O.prototype; // new O();
obj.__proto__ = obj1;
return obj;
})
复制代码
结合instanceof内部机制很容易得出正确答案。
若是稍微调整一下代码顺序,结果将迥然不一样
functionF() {}
functionO() {}
var obj = new O();
O.prototype = new F();
console.log(obj instanceof O); // falseconsole.log(obj instanceof F); // falseconsole.log(obj.__proto__ === O.prototype); // falseconsole.log(obj.__proto__.__proto__ === F.prototype); // false
复制代码
具体缘由,请读者自行分析,若是仍是有疑问,能够在评论区提出!
其实上面不少问题都是考察原型链相关的知识,这里给出一张必须理解的原型链图,原谅我盗了一张图。
问到这里个人脑壳已经有点浆糊了,原谅我太菜了!!8.下面代码输出什么?
for(var i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i)
}, 0)
}
复制代码
答案: 10个10
若要输出从0到9,怎么办?
答案: 将var改成let,或者使用闭包。
// 使用闭包for(var i = 0; i < 10; i++) {
(function (i) {
setTimeout(() => {
console.log(i)
}, 0);
})(i);
}
复制代码
答案: 默认指向在定义它时,它所处的对象,而不是执行时的对象,定义它的时候,可能环境是window(即继承父级的this)。
若是对This还有不清楚的地方,能够参考个人另外一篇文章完全理解JavaScript中的this。
11.说一下你对generator的了解?
答案: 建议你们查看阮一峰老师的generator相关章节
12.使用过flex布局吗?flex-grow和flex-shrink属性有什么用?
答案: flex-grow:项目的放大比例,默认为0,即若是存在剩余空间,也不放大。flex-shrink:项目的缩小比例,默认为1,即若是空间不足,该项目将缩小。
想完全理解flex,能够查看阮一峰老师的Flex布局教程:语法篇
说一下macrotask 和 microtask?并说出下面代码的运行结果。
console.log('a'); setTimeout(() => { console.log('b'); }, 0); console.log('c'); Promise.resolve().then(() => { console.log('d'); }) .then(() => { console.log('e'); });
console.log('f');
答案: 输出结果为 acfdeb,而关于macrotask和microtask能够继续留意笔者后篇文章,亦可自行搜索。不过能够看一下盗的一张图。
14. Http请求中的keep-alive有了解吗。答案:
在http早期,每一个http请求都要求打开一个tpc socket链接,而且使用一次以后就断开这个tcp链接。 使用keep-alive能够改善这种状态,即在一次TCP链接中能够持续发送多份数据而不会断开链接。经过使用keep-alive机制,能够减小tcp链接创建次数,也意味着能够减小TIME_WAIT状态链接,以此提升性能和提升httpd服务器的吞吐率(更少的tcp链接意味着更少的系统内核调用,socket的accept()和close()调用)。 可是,keep-alive并非免费的午饭,长时间的tcp链接容易致使系统资源无效占用。配置不当的keep-alive,有时比重复利用链接带来的损失还更大。因此,正确地设置keep-alive timeout时间很是重要。
**答案:**请看这篇文章react-router的实现原理
17.数组扁平化处理:实现一个flatten方法,使得输入一个数组,该数组里面的元素也能够是数组,该方法会输出一个扁平化的数组。
// Examplelet givenArr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10];
let outputArr = [1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10]
// 实现flatten方法使得
flatten(givenArr)——>outputArr
复制代码
年轻的我是用递归实现的QAQ,个人答案
functionflatten(arr){
var res = [];
for(var i=0;i<arr.length;i++){
if(Array.isArray(arr[i])){
res = res.concat(flatten(arr[i]));
}else{
res.push(arr[i]);
}
}
return res;
}
复制代码
其实你还能够这样
functionflatten(arr){
return arr.reduce(function(prev,item){
return prev.concat(Array.isArray(item)?flatten(item):item);
},[]);
}
复制代码
还可使用ES6拓展运算符
functionflatten(arr){
while(arr.some(item=>Array.isArray(item)){
arr = [].concat(...arr);
}
return arr;
}
复制代码
18.若是在17问的前提下,要作去重和排序处理又该怎么作(不用给出具体代码)。
**答案:**最好封装一个数组方法的类,该类包含flatten(扁平化)、sort(排序)和unique(去重)等方法。