前端全部面试题
https://blog.csdn.net/qq_40055200/article/details/104637574
es6面试题
1.const let var 区别?
一、变量提升
var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined
let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错
二、块级作用域
var不存在块级作用域
let和const存在块级作用域
三、重复声明
var允许重复声明变量
let和const在同一作用域不允许重复声明变量
四、修改声明的变量
var和let可以
const声明一个只读的常量。一旦声明,常量的值就不能改变,但对于对象和数据这种引用类型,内存地址不能修改,可以修改里面的值。
使用场景
2.变量提升:变量提升会优先声明
变量提升意思是 var声明变量时 先声明 再赋值
var a = 5;
function test3(){
var a;
cosnole.log(a)
}
test3(); ------------>undefined
var a = 5;
function test3(){
var a = 3;
console.log(a)
}
test3() -------------->3 (变量提升)
函数提升:将整个代码块提升到他所在的作用域,最开始执行
var a = 1;
function foo() {
var a = function(){} ----->函数提升
a = 10;
console.log(a)------------10
return
}
foo()
console.log(a)--------------1
匿名函数不会被提升
3.什么是匿名函数
匿名函数,就是没有名字的函数。
作用:
语法:
解释:
什么是创建一个函数后,立即调用该函数,调用后,立即释放?
问题:如果不用函数包裹,声明的变量都是全局变量,全局变量既不会自动自动释放,浪费内存,又会造成全局污染。
解决:下·函数的调用结束而自动释放,不占用内存---避免全局污染
(function(){...})()
JS匿名函数理解 - 辉夜 - 博客园
js匿名函数括号的作用_杭电茶娃的博客-CSDN博客
4.JS执行上下文(Execution Context)
代码从上往下开始执行的过程,其实对应一个执行环境,就是执行上下文,当代码执行完,上下文也就会被销毁。
运行环境:
执行上下文的基本构成图
一个执行期上下文的生命周期可以分为两个阶段:
变量对象的创建过程(有时间了解)
5.执行栈
let a = 'Hello World';
function first(){
console.log('Inside first function')
second()
console.log('Again inside first function');
}
function second() {
console.log('Inside second function');
}
first();
//执行顺序
//先执行second(),在执行first()
js中的执行上下文 - 简书
JS夯实之执行上下文与词法环境 - 掘金
6.js中this对象的指代
其实this就是执行上下文的一个属性,执行上下文有3个重要的属性,作用域链(ScopeChain),变量对象(VO)和this .this是在进入执行上下文时确定的,也就是函执行时才确定,并且在运行期间不允许修改并且是永久不变的。
// 全局代码中this
在全局代码中this是不变的,this始终是全局对象本身
var a = 10;
this.b = 20;
window.c = 30;
console.log(this.a);
console.log(b)
console.log(this.c)
console.log(this === window) // true
// 由于this就是全局对象window,所以上述 a ,b ,c 都相当于在全局对象上添加相应的属性
如果我们在代码运行期尝试修改this的值,就会抛出错误:
this = { a : 1 } ; // Uncaught SyntaxError: Invalid left-hand side in assignment
console.log(this === window) // true
7.如何判断一个对象是否属于某个类
if(()spear instanceof Array){console.log('yes');}
instanceof:判断构造函数的prototype属性是否出现在对象的原型链的任何位置
8.箭头函数,使用箭头函数应注意什么?
优点:
箭头函数不会绑定this,会捕获其所在上下文的this,作为自己的this.(注意:这句话需要注意的是,箭头函数的外层如果有普通函数,那么箭头函数的this就是这个外层的普通函数的this,箭头函数的外层如果没有普通函数,那么箭头函数的this就是全局变量。箭头函数没有自己的this,它的this是继承而来,默认指向在定义它时所处的对象(宿主对象))
箭头函数不绑定argument,取而代之用rest参数解决,同时没有super和new.target(注意:箭头函数没有arguments、super、new.target的绑定,这些值由外围最近一层非箭头函数决定。)
使用call,apply,bind并不会改变箭头函数中this的指向
原因:
箭头函数没有原型对象prototype这个属性
不能使用yield关键字,不能用作generator函数
为什么不能用做构造函数?
构造函数是通过new关键字来生成对象实例,生成对象实例的过程也是通过构造函数给实例绑定this的过程,而箭头函数没有自己的this。创建对象过程,new 首先会创建一个空对象,并将这个空对象的__proto__指向构造函数的prototype,从而继承原型上的方法,但是箭头函数没有prototype。因此不能使用箭头作为构造函数,也就不能通过new操作符来调用箭头函数。
举例子:
箭头函数的写法:
// ES5
var x = function(x, y) {
return x * y;
}
// ES6;两者等价
const x = (x, y) => x * y;
const x = (x, y) => { return x * y };
// 1.相比普通函数,箭头函数有更加简洁的语法
普通函数
function add(num){
return num+10
}
箭头函数
const add = num => num + 10;
//2.箭头函数不绑定this,会捕获其所在上下文的this,作为自己的this
下面是箭头函数的外层有普通函数
let obj = {
fn:function(){
console.log('我是普通函数',this === obj) // true
return () =>{
console.log('我是箭头函数',this === ojb) // true
}
}
}
console.log(obj.fn())
下面是箭头函数的外层没有普通函数
let obj = {
fn: () =>{
console.log(this === window)
}
}
console.log(obj.fn()) // true
// 3.箭头函数是匿名函数,不能作为构造函数,不可以使用new命令,否则会抛出错误
let f = () => {};
let t = new f(); // f is not a constructor
// 4.箭头函数不绑定arguments,取而代之用rest参数解决,同时没有super和new.target。
下面的这个函数会报错,在浏览器环境下
let f = ()=>console.log(arguments);
//报错
f(); // arguments is not defined
下面的箭头函数不会报错,因为arguments是外围函数的。
function fn(){
let f = ()=> {
console.log(arguments)
}
f();
}
fn(1,2,3) // [1,2,3]
箭头函数可以通过拓展运算符获取传入的参数。
const testFunc = (...args) =>{
console.log(args) [[1,2,3]],undefined
}
testFunc([1,2,3])
// 5.使用call,apply,bind并不会改变箭头函数中的this指向
window.name = "window_name";
let f1 = function () {
return this.name;
};
let f2 = () => this.name;
let obj = { name: "obj_name" };
console.log(f1.call(obj)); //obj_name
console.log(f2.call(obj)); // window_name
console.log(f1.apply(obj)); // obj_name
console.log(f2.apply(obj)); // window_name
console.log(f1.bind(obj)()); // obj_name
console.log(f2.bind(obj)()); // window_name
// 6.箭头函数没有原型对象prototype这个属性
let F = ()=>{};
console.log(F.prototype) // undefined
arguments辨析
这一次,彻底搞懂箭头函数_Always--Learning的博客-CSDN博客
9.模板字符串
模版字符串,用`(反引号)标识,用${}将变量括起来。
var name="zzw";
`${name},no matter what you do,I trust you.`
ES6模板字符串 - WhiteSpace - 博客园
10. ... 展开运算符(扩展运算符)
可以将数组或对象里面的值展开;还可以将多个值收集为一个变量
// 数组合并
var array1 = [1, 2, 3,4];
var array2 = [4, 5, 6];
var array3 = [...array1, ...array2, 7, 8]; //[1,2,3,4,4,5,6,7,8]
array1.push(...array2 )// 当然也可以使用concat等数组合并方法,但是扩展运算符提供了一种新的方式
var items = [1,2,3];
var newArr = [...items,4]
console.log(newArr); // [1,2,3,4]
var obj = {name:"zs",age:12};
var obj2 = {age:14,addr:"gz"}
console.log({...obj,...obj2}); // {name:"zs",age:14,addr:"gz"}
11.解构赋值
所谓的解构赋值其实就是分解出一个对象的解构,分成两个步骤:
let node = {
type: "Identifier",
name: "foo"
};
let { type, name } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"
数组解构
基本:let [a, b, c] = [1, 2, 3];// a = 1 // b = 2 // c = 3
可嵌套:let [a, [[b], c]] = [1, [[2], 3]]; // a = 1 // b = 2 // c = 3
可忽略:let [a, , b] = [1, 2, 3]; // a = 1 // b = 3
不完全解构:let [a = 1, b] = []; // a = 1, b = undefined
剩余运算符:let [a, ...b] = [1, 2, 3]; //a = 1 //b = [2, 3]
字符串等:let [a, b, c, d, e] = 'hello'; // a = 'h' // b = 'e' // c = 'l' // d = 'l' // e = 'o'
对象模型解构
基本:
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
// foo = 'aaa'
// bar = 'bbb'
let { baz : foo } = { baz : 'ddd' };
// foo = 'ddd'
可嵌套可忽略
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { y }] } = obj;
// x = 'hello'
// y = 'world'
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { }] } = obj;
// x = 'hello'
不完全解构
let obj = {p: [{y: 'world'}] };
let {p: [{ y }, x ] } = obj;
// x = undefined
// y = 'world'
剩余运算符
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40};
// a = 10
// b = 20
// rest = {c: 30, d: 40}
解构默认值
let {a = 10, b = 5} = {a: 3};
// a = 3; b = 5;
let {a: aa = 10, b: bb = 5} = {a: 3};
// aa = 3; bb = 5;
12.promise(异步)--解决异步问题
需要整理:异步编程 promise · 语雀
原理:巨大提升!更快的 async 函数和 promises - 掘金
问题:【建议星星】要就来45道Promise面试题一次爽到底(1.1w字用心整理) - 掘金
目的:解决回调地狱,让程序开发者编写的代码具有更好的可读性
promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
优点:
promise是回调地狱的一个解决方案,在没有Promise 之前,如果异步任务比较多,并且有相互依赖的作用,就只能使用回调函数的方式来处理,这样就会形成回调地狱,代码可读性和可维护性会很差。
promise 的 then 方法支持链式调用,很好的解决了之前使用回调函数的书写方式,使代码逻辑很有条理
缺点:
但是Promise 也是有缺点的,首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
2个特点:
var promise = new Promise(function(resolve, reject){
// ... some code
if (/* 异步操作成功 */) {
resolve(value);
} else {
reject(error);
}
})
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由JavaScript引擎提供,不用自己部署。
resolve作用是将Promise对象状态由“未完成”变为“成功”,也就是Pending -> Fulfilled
,在异步操作成功时调用,并将异步操作的结果作为参数传递出去;而reject函数则是将Promise对象状态由“未完成”变为“失败”,也就是Pending -> Rejected
,在异步操作失败时调用,并将异步操作的结果作为参数传递出去。
promise基本流程图:
then:
Promise实例生成后,可用then
方法分别指定两种状态回调参数。then 方法可以接受两个回调函数作为参数:
routeInfo (type = 'edit') {
return new Promise((resolve, reject) => {
this.listData(type).then(result => {
return new Promise((resolve) => {
let res = result.list[0]
if (result.list.length !== 1) {
console.warn('待办结果不唯一')
}
resolve(res)
})
}).then(res => {
this.dataValidator(res, type).then(res => {
resolve({
name: this.info[this.typeCode][type].routerName,
query: this.info[this.typeCode][type].query(res),
params: this.info[this.typeCode][type].params && this.info[this.typeCode][type].params(res)
})
}).catch(e => {
reject(e)
})
}).catch(e => {
reject(e)
})
})
}
all:多个请求一起发出并根据请求顺序获取和使用数据的场景
getData () {
Promise.all([
this.getCreditData(),
this.getProjectData()
]).then(result => {
}).finally(() => {
this.loading.detail = false
})
},
catch:reject状态时才会进入,捕获错误信息
let p2 = new Promise((resolve, reject) => {
reject('123');
}).catch(e => e);
finally() :不管Promise对象成功失败都进finally,都会执行的操作
Promise.then(result => {}).catch(error => {}).finally(() =>{})
图灵社区
promise.all和promise.race的区别和常见
all:将多个实例组装个成一个新实例,成功的时候返回一个成功的数组;失败的时候则返回最先被reject失败状态的值。
race:是数组中的任务哪个获取的块,就返回哪个,不管结果本身是成功还是失败
// all
let wake=(time)=>{
return new Promise(function (resolve,reject){
setTimeout(()=>{
resolve(`${time/1000}后醒来`);
},time);
});
}
let p1=wake(10000);
let p2=wake(1000);
Promise.all([p1,p2]).then(res=>{
let [res1,res2]=res;
console.log(res1,res2);
}).catch(err=>{
console.log(err);
})
// race
let p1=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('success');
}, 10000);
});
let p2=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('faild');
}, 500);
});
Promise.race([p1,p2]).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err); // 返回的是faild
})
Promise、Async有什么区别
Promise 和 Async/await 均是 JavaScript 异步编程的方式。它们的主要区别在于语法和用法的不同。
Promise 是一种异步编程的方式,它通过 chaining(链式调用)的方式将一组异步操作的结果组合成可读性强的代码块,避免了回调地狱的问题。Promise 有三种状态:pending(进行中)、fulfilled(已成功完成)、rejected(已失败)。通过 then() 方法对象可以传递当前 Promise 对象的处理后的结果,以及通过 catch() 处理当前 Promise 对象发生的异常。
async/await 是 ES6 中提供的异步编程方式,相对于 Promise 更为直观和易懂,它可以使异步代码看起来像同步代码。async/await 在语法上是基于 Promise,它通过 async 声明的函数返回一个 Promise 对象,await 关键字则是等待 Promise 对象的 resolve。async/await 可以多次 await,但也不能滥用。
虽然 async/await 更易于理解和编写,但在某些场景下,Promise 会比 async/await 更为灵活。例如在使用 Promise.all(),将多个异步操作一起执行时,Promise 执行起来可以更有效率。
13.异步代码执行结果
// 说出下面代码执行结果
const promise = new Promise((resolve,reject)=>{
console.log(1);
resolve();
console.log(2);
reject()
})
setTimeout(()=>{console.log(5)},0)
promise.then(()=>{console.log(3)})
.then(()=>{console.log(6)})
.catch(()=>{console.log(7)})
console.log(4)
答案是1,2,4,3,6,5
首先new Promise时候打印1和2,因为new Promise时候会立即执行传入的方法
然后后面代码都是异步代码,先将setTimeout的回调加入宏任务队列,再把promise.then放入到微任务队列,然后直接执行最后一句,打印4
这样宏任务代码执行完了,接下来开始执行微任务队列中的任务,由于promise resolve,因为promise resolve之后状态不会再改变,因此不会执行到reject的对调,所以打印3和6
微任务队列为空,再到宏任务队列中查找任务,找到setTimeout回调执行,打印5
调用栈、宏任务队列、微任务队列都为空,代码执行结束。
14.下面的输出结果是多少
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve();
console.log(2);
})
promise.then(() => {
console.log(3);
})
console.log(4);
Promise 新建后立即执行,所以会先输出 1,2,而 Promise.then()内部的代码在 当次 事件循环的 结尾 立刻执行 ,所以会继续输出4,最后输出3
15.Symbol(第七种基本数据类型)
Symbol是一种基本类型。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的
因此:使用JSON.stringify()将对象转成JSON字符串的时候,Symbol这个属性也会排除在外
(1)为什么引入Symbol?
之前的对象属性名是字符串,容易造成属性名冲突
(2)typeof运算符用于Symbol类型值,返回symbol
let name = Symbol()
console.log(typeof name) // Symbol
(3)Symbol的值和谁都不相等,是独一无二的值.
let symbol1 = Symbol()
let symbol2 = Symbol()
console.log(symbol1 === symbol2) // false
console.log(symbol1 == symbol2) // false
symbol1和symbol2相等吗?
不相等.因为Symbol类型的值是独一无二的值.
(4).为什么Symbol不能用new关键字?
let obj = new Symbol() // TypeError
symbol值不是对象,所以不能添加属性
(5)console.log(Symbol(‘Alice’) + “bruce”) // TypeError,为什么错误?
Symbol值不能与其他类型的值进行运算
(6)如何读取Symbol的属性值?
let name = Symbol()
let obj = {}
obj[name] = “Alice”
cosnole.log(obj[name])
Symbol值定义属性时,必须放在方括号内,不能用点运算符。
(7)Symbol的值显示的转成字符串或者布尔值,但是不能转成数值.
(8)获取对象属性的两种方法
Object.getOwnPropertySymbols() 和 Object.getOwnPropertyNames()
16.解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值
类模板字符串的功能
let name = 'web';
let age = 10;
let str = '你好,${name} 已经 ${age}岁了'
str = str.replace(/\$\{([^}]*)\}/g,function(){
return eval(arguments[1]);
})
console.log(str);//你好,web 已经 10岁了
js面试笔试--ES6的解构_evior-CSDN博客
17.babel是什么,有什么作用?
babel是一个 ES6 转码器,可以将 ES6 代码转为 ES5 代码,以便兼容那些还没支持ES6的平台。
18.使用结构赋值,实现两个变量的值的交换
let a = 1;let b = 2;
[a,b] = [b,a];
15.ES6 怎么写 class ,为何会出现 class ?
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
19.import、export导入导出
将JS代码分割成不同功能的小块进行模块化,将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块的导入的方式可以在其他地方使用
20.ES6中可以使用哪些关键字来实现继承 ?
ES6实现继承实际上是通过关键字extends
、super来完成的
。
super关键字用法:
1.直接当成函数使用,表示调用父类的构造器
2.当成对象使用,表示父类的原型
21.es6继承,子类会继承父类的静态成员吗?
会继承,除了私有属性,父类的所有属性和方法,都会被子类继承,其中包括静态方法。
22.ES6继承为什么需要super?不执行super有什么问题?
super关键字,它在这里表示父类的构造函数,用来新建父类的this对象。
如果存在继承,则子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。
23.定义在Class里的方法定义在类上面还是原型上面?
方法定义在原型上,属性定义在实例上。
class Test {
// 实例上
name = '';
// 原型上
log() {}
// 实例上
log1 = () => {};
}
24.requireJS的核心原理是什么?
require.js 的核心原理是通过动态创建 script 脚本来异步引入模块,然后对每个脚本的 load 事件进行监听,如果每个脚本都加载完成了,再调用回调函数。
25.es6模块和commonjs模块有什么不同
ES6 Module和CommonJS模块的区别:
ES6 Module和CommonJS模块的共同点:
什么是Proxy? (代理--不会)
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”,即对编程语言进行编程。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
flat
数组扁平化:flat
arr.flat([depth])
depth 是 flat 的参数,depth 是可以传递数组的展开深度(默认不填、数值是 1),即展开一层数组。如果层数不确定,参数可以传进 Infinity,代表不论多少层都要展开:
let arr = [1,[2,[3,4]]]
function flatten(arr){
return arr.flat(Infinity)
}
console.log(flatten(arr)) // [1,2,3,4,5]
实现数组的flat方法
function _flat(arr,depth){
if(!Array.isArray(arr) || depth <= 0){
return arr;
}
return arr.reduce((prev,cur) =>{
if(Array.isArray(cur)){
return prev.concat(_flat(cur,depth - 1))
}else{
return prev.concat(cur)
}
},[])
}
================开始不用看
三种事件模型是什么?
事件 是用户操作网页时发生的交互动作或者网页本身的一些操作,现代浏览器一共有三种事件模型。
DOM0级模型: ,这种模型不会传播,所以没有事件流的概念,但是现在有的浏览器支持以冒泡的方式实现,它可以在网页中直接定义监听函数,也可以通过 js属性来指定监听函数。这种方式是所有浏览器都兼容的。
IE 事件模型: 在该事件模型中,一次事件共有两个过程,事件处理阶段,和事件冒泡阶段。事件处理阶段会首先执行目标元素绑定的监听事件。然后是事件冒泡阶段,冒泡指的是事件从目标元素冒泡到 document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。这种模型通过 attachEvent 来添加监听函数,可以添加多个监听函数,会按顺序依次执行。
DOM2 级事件模型: 在该事件模型中,一次事件共有三个过程,第一个过程是事件捕获阶段。捕获指的是事件从 document 一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。后面两个阶段和 IE 事件模型的两个阶段相同。这种事件模型,事件绑定的函数是 addEventListener,其中第三个参数可以指定事件是否在捕获阶段执行。
92.JS中的宿主对象与原生对象有何不同?( 请指出 JavaScript 宿主对象 (host objects) 和原生对象 (native objects) 的区别?)
宿主对象:这些是运行环境提供的对象。这意味着它们在不同的环境下是不同的。例如,浏览器包含像windows
这样的对象,但是Node.js环境提供像Node List
这样的对象。 Javascript内置对象、原生对象、宿主对象关系_每天=生命的最后一天-CSDN博客
原生对象:这些是JS中的内置对象。它们也被称为全局对象,因为如果使用JS,内置对象不受是运行环境影响。
js 获取原型的方法?
从构造函数获得原型对象: 构造函数.prototype
从对象实例获得父级原型对象:1.对象实例._proto_ 2.Object.getPrototypeOf(对象实例)
function Student(){
this.name = "小马扎";
this.age = 18;
}
var lilei = new Student(); // 创建对象实例
console.log(Student.prototype); //Student{}
console.log(lilei.__proto__); //Student{}
console.log(Object.getPrototypeOf(lilei)); //Student{}
JS中为什么需要原型对象
JS使用构造函数创建对象时,每个实例对象的方法都存放在独立的内存中,不能共享;使用原型对象可以解决上面浪费内存空间。
https://jingyan.baidu.com/article/597a0643a743aa712b52439b.html
JavaScript如果实现继承?
1、构造函数继承
2、原型链继承
3、实例继承
4、拷贝继承
原型prototype机制或apply和call方法去实现较简单、建议使用构造函数与原型混合方式
function Parent(){
this.name = "shen";
}
function Child(){
this.age = 23;
}
Child.prototype = new Parent();
var Demo = new Child();
console.log(Demo.age);
console.log(Demo.name);
JavaScript原型、原型链?有什么特点?
什么是原型:原型是一个对象、其他对象可以通过它实现属性继承(任何对象都可以成为原型)
所有对象在默认情况下都有一个原型(原型本身就是个对象)
什么是对象(任何无序键值对的集合)如果它不是基本数据类型、那它就是一个对象
原型链:当我们访问这个对象的属性时、如果这个对象内部不存在这个属性、那么他就回去prototype里去查找、这个prototype又有自己的prototype属性。这样一直找下去。就是平时说的原型链概念
关系:instance.constructor.prototype = instance.__proto__
当我们需要一个属性时、JavaScript引擎会先查看当前对象中是否有这个属性
如果没有、就会查找他的prototype对象是否有这个属性、依次递推下去、一直检索到Object内检对象
function Func(){}
Func.prototype.name = "shen";
Func.prototype.getInfo = function(){
return this.name;
}
var person = new Func();
console.log(person.getInfo());
console.log(Func.prototype);
var a = {};
a.__proto__ = Array.prototype;
a.length;
创建a、然后通过a的原型来达到继承Array这个已经存在的对象的功能。
原型真正的美丽提现在多个实例、共用一个通用原型
原型对象的属性一旦定义、就可以被多个引用它的实例所继承、性能和未还的意义是很强的(这也是构造函数存在的意义)
每个函数都有一个原型属性。JavaScript没有在构造函数(constructor)和其他函数之间做区分。
什么是ES6迭代器
请分别用深度优先思想和广度优先思想实现一个拷贝函数?
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/10
ES5/ES6 的继承除了写法以外还有什么区别?
先看ES5的继承(原型链继承)
function a() {
this.name = 'a';
}
a.prototype.getName = function getName() {
return this.name
}
function b() {}
b.prototype = new a();
console.log(b.prototype.__proto__ === a.prototype); // true
console.log(b.__proto__ === a); // false
console.log(b.__proto__); // [Function]
ES6继承
class A {
constructor(a) {
this.name = a;
}
getName() {
return this.name;
}
}
class B extends A{
constructor() {
super();
}
}
console.log(B.prototype.__proto__ === A.prototype); // true
console.log(B.__proto__ === A); // true
console.log(B.__proto__); // [Function: A]
对比代码可以知道,子类的继承都是成功的,但是问题出在,子类的 __proto__
指向不一样。
ES5
的子类和父类一样,都是先创建好,再实现继承的,所以它们的指向都是 [Function]
。
ES6
则得到不一样的结果,它指向父类,那么我们应该能推算出来,它的子类是通过 super
来改造的。
根据 es6--阮一峰 在class继承里面的说法,是这样子的:
引用阮一峰的 ECMAScript6入门
的class继承篇
子类必须在constructor
方法中调用super
方法,否则新建实例时会报错。这是因为子类自己的this
对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super
方法,子类就得不到this
对象。
ES5 的继承,实质是先创造子类的实例对象this
,然后再将父类的方法添加到this
上面(Parent.apply(this)
)。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this
上面(所以必须先调用super
方法),然后再用子类的构造函数修改this
。
1、class 声明会提升,但不会初始化赋值。Foo 进入暂时性死区,类似于 let、const 声明变量。
2、class 声明内部会启用严格模式。
3、class 的所有方法(包括静态方法和实例方法)都是不可枚举的。
4、class 的所有方法(包括静态方法和实例方法)都没有原型对象 prototype,所以也没有[[construct]],不能使用 new 来调用。
5、必须使用 new 调用 class。
6、class 内部无法重写类名
setTimeout、Promise、Async/Await 的区别
其中settimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行; promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行;async函数表示函数里面可能会有异步方法,await后面跟一个表达式,async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行。
谈谈以前端角度出发做好SEO需要考虑什么?
Meta标签优化
主要包括主题(Title),网站描述(Description),和关键词(Keywords)。还有一些其它的隐藏文字比如Author(作者),Category(目录),Language(编码语种)等。
合理的标签使用
JavaScript中、有一个函数、执行对象查找时、永远不会去查找原型、这个
hasOwnProperty:当前函数返回的是一个布尔值、指出一个对象是否具有指定名称的属性、此方法无法检查该对象的原型链中是否具有该属性(该属性必须是对象本身的一个成员属性)
object.hasOwnProperty(prName);
参数object是必选项、一个对象是实例
参数proName是必选项。一个属性名称的字符串值。
如果object具有制定名称的属性、那么JavaScript中的hasOwnProperty函数方法返回true、反之则返回false
JavaScript设计模式
52.ajax原理:
60.输出今天的日期,以YYYY-MM-DD的方式,比如今天是2014年9月26日,则输出2014-09-26
考点:日期对象Date相关API的使用 var d = new Date();
65.foo = foo||bar ,这行代码是什么意思?为什么要这样写?
var foo;
if(foo){
foo=foo;
}else{
foo=bar;
}
答案:常用于函数参数的空判断
短路表达式:作为”&&”和”||”操作符的操作数表达式,这些表达式在进行求值时,只要最终的结果已经可以确定是真或假,求值过程便告终止,这称之为短路求值。
考点:if条件的真假判定
记住以下是false的情况:空字符串、false、undefined、null、0
(头条、微医)Async/Await 如何通过同步的方式实现异步
async await 用于把异步请求变为同步请求的方式,第一个请求的返回值作为后面一个请求的参数,其中每一个参数都是一个promise对象
例如:这种情况工作中会经常遇到
(async () => {
var a = await A();
var b = await B(a);
var c = await C(b);
var d = await D(c);
})();
(头条)异步笔试题
请写出下面代码的运行结果
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
(携程)算法手写题
已知如下数组:
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
编写一个程序将数组扁平化去并除其中重复部分数据,最终得到一个升序且不重复的数组
var arr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10];
// 方法一
console.log(Array.from(new Set(arr.flat(Infinity))).sort((a, b) => a - b))
// 方法二
console.log(Array.from(new Set(arr.toString().split(','))).map(Number).sort((a, b) => a - b))
// 方法三
// 第一步:扁平化
let newArr = [];
function flat(originArr) {
if ({}.toString.call(originArr) === '[object Array]') {
for (let i of originArr) {
if ({}.toString.call(i) === '[object Array]') {
arguments.callee(i)
} else {
newArr.push(i)
}
}
}
return newArr;
}
console.log(flat(arr))
// 第二步:去重
var newArr1 = [];
for (let i of newArr) {
if (!newArr1.includes(i)) newArr1.push(i);
}
// 第三步:排序 可以采用相关算法处理
console.log(newArr1.sort((a, b) => a - b))
(兑吧)情人节福利题,如何实现一个 new
先理清楚 new 关键字调用函数都的具体过程,那么写出来就很清楚了
首先创建一个空的对象,空对象的 ___proto____属性指向构造函数的原型对象
把上面创建的空对象赋值构造函数内部的this,用构造函数内部的方法修改空对象
如果构造函数返回一个非基本类型的值,则返回这个值,否则上面创建的对象
function _new(fn, ...arg) {
var obj = Object.create(fn.prototype);
const result = fn.apply(obj, ...arg);
return Object.prototype.toString.call(result) == '[object Object]' ? result : obj;
}
(网易)简单讲解一下http2的多路复用
第 15 题:简单讲解一下 http2 的多路复用 · Issue #14 · Advanced-Frontend/Daily-Interview-Question · GitHub
谈谈你对TCP三次握手和四次挥手的理解
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/15
A、B 机器正常连接后,B 机器突然重启,问 A 此时处于 TCP 什么状态
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/21
介绍下 npm 模块安装机制,为什么输入 npm install 就可以自动安装对应的模块?
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/22
找出多维数组最大值
给字符串新增方法实现功能
找出字符串出现最多次数的字符以及次数
sort背后原理是什么?
JavaScript 中 this 是如何工作的
JavaScript 中 this 是如何工作的 ? - 前端の战士 - 博客园
一般this指向调用者,箭头函数的this,指向调用的父作用域
call ,apply,bind修改this
页面重构怎么操作?
js继承的6种方式
JS实现继承的几种方式 - 幻天芒 - 博客园
new实现
js new一个对象的过程,实现一个简单的new方法 - 听风是风 - 博客园
列出JS中的一些设计模式:
如何在现有函数中添加新属性
只需给现有函数赋值,就可以很容易地在现有函数中添加新属性。例如,现有一个对象person
,通过下面的代码来为 person
添加新的属性:
person.country= “India”;
JavaScript 原型,原型链?有什么特点?
每个对象都会在其内部初始化一个属性,就是prototype(原型)==(在JavaScript中,每个函数都有一个prototype属性,这个属性指向函数的原型对象。)
function Person(age) {
this.age = age
}
Person.prototype.name = 'kavin'
var person1 = new Person()
var person2 = new Person()
console.log(person1.name) //kavin
console.log(person2.name) //kavin
javascript——原型与原型链 - 雅昕 - 博客园
原型链:当我们去访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里面找这个属性,这个属性prototype就会有自己的prototype。
就这样一层一层的寻找,也就是我们平时所说的原型链的概念。
关系
instance.constructor.prototype=instance._proto_
JavaScript 对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与
之相关的对象也会继承这一改变。
谈谈你对模块化开发的理解?
js 的几种模块规范?
js 中现在比较成熟的有四种模块加载方案:
第一种是 CommonJS 方案,它通过 require 来引入模块,通过 module.exports 定义模块的输出接口。这种模块加载方案是服务器端的解决方案,它是以同步的方式来引入模块的,因为在服务端文件都存储在本地磁盘,所以读取非常快,所以以同步的方式加载没有问题。但如果是在浏览器端,由于模块的加载是使用网络请求,因此使用异步加载的方式更加合适。
第二种是 AMD 方案,这种方案采用异步加载的方式来加载模块,模块的加载不影响后面语句的执行,所有依赖这个模块的语句都定义在一个回调函数里,等到加载完成后再执行回调函数。require.js 实现了 AMD 规范。
第三种是 CMD 方案,这种方案和 AMD 方案都是为了解决异步模块加载的问题,sea.js 实现了 CMD 规范。它和require.js的区别在于模块定义时对依赖的处理不同和对依赖模块的执行时机的处理不同。
第四种方案是 ES6 提出的方案,使用 import 和 export 的形式来导入导出模块。这种方案和上面三种方案都不同。
61.JavaScript事件循环机制相关问题
关键字:单线程非阻塞、执行栈、事件队列、宏任务(setTimeout()、setInterval(),setTimeout、setInterval、script、setImmedate、IO、Promise.resolve)、微任务(new Promise(),process.nextTick、Promise、async await、mutation observer)
setTimeout(function () {
console.log(1);
});
new Promise(function(resolve,reject){
console.log(2)
resolve(3)
}).then(function(val){
console.log(val);
})
console.log(4);
// 2
// 4
// 3
// 1
先按顺序执行同步任务,Promise新建后立即执行输出2,接着输出4,异步任务等同步任务执行完后执行,且同一次事件循环中,微任务永远在宏任务之前执行。这时候执行栈空了,执行事件队列,先取出微任务,输出3,最后取出一个宏任务,输出1。
事件循环--浏览器
执行宏任务,然后执行该宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。
对象是什么?
arguments对象是函数中传递的参数值的集合。它是一个类似数组的对象,因为它有一个length属性,我们可以使用数组索引表示法arguments[1]来访问单个值,但它没有数组中的内置方法,如:forEach、reduce、filter和map。
我们可以使用Array.prototype.slice将arguments对象转换成一个数组。
function one() {
return Array.prototype.slice.call(arguments);
}
注意:箭头函数中没有arguments对象。
function one() {
return arguments;
}
const two = function () {
return arguments;
}
const three = function three() {
return arguments;
}
const four = () => arguments;
four(); // Throws an error - arguments is not defined
当我们调用函数four时,它会抛出一个ReferenceError: arguments is not defined error
。使用rest语法,可以解决这个问题
const four = (...args) => args;
这会自动将所有参数值放入数组中。
ES6 模块与 CommonJS 模块、AMD、CMD 的差异。
https://blog.csdn.net/u013681954/article/details/97299399
generator
调用之后会返回一个value、next 和done,value表示当前的值,done表示是否结束,结束后值为 true,每次执行都需要调用next才会继续执行
9.修饰器 @
decorator是一个函数,用来修改类甚至于是方法的行为。修饰器本质就是编译时执行的函数
10.class 类的继承
ES6中不再像ES5一样使用原型链实现继承,而是引入Class这个概念
23.Promise 中reject 和 catch 处理上有什么 区别
reject 是用来抛出异常,catch 是用来处理异常
reject 是 Promise 的方法,而 catch 是 Promise 实例的方法
reject后的东西,一定会进入then中的第二个回调,如果then中没有写第二个回调,则进入catch
网络异常(比如断网),会直接进入catch而不会进入then的第二个回调
14.Proxy代理
使用代理(Proxy)监听对象的操作,然后可以做一些相应事情
15.ECMAScript 6 怎么写 class ,为何会出现 class?
ES6的class可以看作是一个语法糖,它的绝大部分功能ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法
//定义类
class Point {
constructor(x,y) {
//构造方法
this.x = x; //this关键字代表实例对象
this.y = y;
} toString() {
return '(' + this.x + ',' + this.y + ')';
}
}
19.下面的输出结果是多少
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve();
console.log(2);
})
promise.then(() => {
console.log(3);
})
console.log(4); //1 2 4 3
Promise 新建后立即执行,所以会先输出 1,2,而 Promise.then()
内部的代码在 当次 事件循环的 结尾 立刻执行 ,所以会继续输出4,最后输出3
20.使用结构赋值,实现两个变量的值的交换
let a = 1;let b = 2;
[a,b] = [b,a];
21.设计一个对象,键名的类型至少包含一个symbol类型,并且实现遍历所有key
let name = Symbol('name');
let product = {
[name]:"洗衣机",
"price":799
};
Reflect.ownKeys(product);
22.下面Set结构,打印出的size值是多少
let s = new Set();
s.add([1]);
s.add([1]);console.log(s.size); //2
两个数组[1]并不是同一个值,它们分别定义的数组,在内存中分别对应着不同的存储地址,因此并不是相同的值。都能存储到Set结构中,所以size为2
24.使用class 手写一个promise
//创建一个Promise的类
class Promise{
constructor(executer){//构造函数constructor里面是个执行器
this.status = 'pending';//默认的状态 pending
this.value = undefined//成功的值默认undefined
this.reason = undefined//失败的值默认undefined
//状态只有在pending时候才能改变
let resolveFn = value =>{
//判断只有等待时才能resolve成功
if(this.status == pending){
this.status = 'resolve';
this.value = value;
}
}
//判断只有等待时才能reject失败
let rejectFn = reason =>{
if(this.status == pending){
this.status = 'reject';
this.reason = reason;
}
}
try{
//把resolve和reject两个函数传给执行器executer
executer(resolve,reject);
}catch(e){
reject(e);//失败的话进catch
}
}
then(onFufilled,onReject){
//如果状态成功调用onFufilled
if(this.status = 'resolve'){
onFufilled(this.value);
}
//如果状态失败调用onReject
if(this.status = 'reject'){
onReject(this.reason);
}
}
}
29.说一下es6的导入导出模块
// 只导入一个 import {sum} from "./example.js" // 导入多个 import {sum,multiply,time} from "./exportExample.js" // 导入一整个模块 import * as example from "./exportExample.js"
导出通过export关键字
//可以将export放在任何变量,函数或类声明的前面
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
//也可以使用大括号指定所要输出的一组变量
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
//使用export default时,对应的import语句不需要使用大括号
let bosh = function crs(){}
export default bosh;
import crc from 'crc';
//不使用export default时,对应的import语句需要使用大括号
let bosh = function crs(){}
export bosh;
import {crc} from 'crc';
13.
堆栈内存(没看)
当浏览器加载页面时,会形成两个虚拟的内存;一个栈内存,堆内存;
栈内存:
堆内存: 存储引用数据类型
;
28.函数的递归
递归: 针对的是函数; 是JS中一种重要的思想;
函数: 分为定义和执行
函数递归: 在函数体内部,调用函数自己本身,让其执行;这就是递归;
function sum(num) {
if(num === 0){
return num;
}
if(num%3===0){
return num + sum(num-1);
}
if(num%3!==0){
return sum(num-1);
}
// return sum(99)
// return 99 + sum(98)
// return 99 + sum(97)
// return 99 + sum(96)
// return 99 + 96 + sum(95)....
// return 99 + 96 +... + 3 + sum(2)
// return 99 + 96 +... + 3 + sum(1)
// return 99 + 96 +... + 3 + 0
}
console.log(sum(100));
console.log(sum(200));
29.求1-100之间是3倍数的和(% : 取模;取余数)
var total = 0;
for(var i=0;i<100;i++){
if(i%3===0){
total += i;
}
}
30.数组的插入排序
var ary = [12,88,67,98,56,35,45,26,1];
//5 6 7 8 10
//得到的新数组是排好序
//插入排序原理:去原有数组中去取每一项,然后和新数组中的成员进行比较,从新数组后面开始,一一向前比较,比新数组项小,继续和前一项比较,直到当前项比数组中一项值大时,把它放到这一项的后面;
var newAry = [];
newAry.push(ary[0]);
for(var i=1;i=0;j--){
if(cur=0;j--){
if(cur
32.随机验证码
var code = document.getElementById("code");
function getCode() {
// 准备一个62个字符串;
// 产生随机数;随机数可以作为字符的索引;
// 随机索引范围【0-61】
var str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 随机数;
var i =0;
var newStr = "";
while(i<4){
var num = Math.round(Math.random()*(61-0)+0);
newStr+=str[num];
i++;
}
code.innerHTML = newStr;
}
getCode();
// 把函数的空间地址赋值给code的onclick属性;
code.onclick = getCode;
43.看下列代码会有什么样的输出?
var foo = "11"+2-"1";
console.log(foo);//112-1=111
console.log(typeof foo);//”number”
考点:
1、数字和字符串都可以用加法运算符,数字和字符串相加,结果就是一个字符串
2、但是减法运算符只能用于两个数字之间,想要执行减法运算,必须把两边数字都变成数字类型的
答案:”111”、”number”
45.已知数组var stringArray = [“This”, “is”, “Baidu”, “Campus”],alert出”This is Baidu Campus”。
考点:数组的join方法的使用,将一个数组通过指定字符分隔组成一个想要的字符串
答案:alert(stringArray.join(“ ”))
46.已知有字符串foo=”get-element-by-id”,写一个function将其转化成驼峰表示法”getElementById”。
function combo(msg){
var arr=msg.split("-");//[get,element,by,id]
for(var i=1;i
47.var numberArray = [3,6,2,4,1,5];
1)实现对该数组的倒排,输出[5,1,4,2,6,3]
function reverseArray(arr){
var result=[];
//方法1:
/*for (var i = arr.length - 1; i >= 0; i--) {
result.push(arr[i]);
}*/
//方法2:
for (var i = 0, len = arr.length; i < len; i++) {
result.unshift(arr[i]);
}
return result;
}
2)实现对该数组的降序排列,输出[6,5,4,3,2,1]
function sortDesc(arr) {
for (var i = 0, len = arr.length; i < len; i++) {
for (var j = i + 1, len2 = arr.length; j < len2; j++) {
//>就是降序 <就是升序
if (arr[j] > arr[i]) {
var temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
}
return arr;
}
51.用js实现随机选取10–100之间的10个数字,存入一个数组,并排序。
var iArray = [];
function getRandom(istart, iend){
var iChoice = iend - istart +1;
return Math.floor(Math.random() * iChoice+ istart);
}
Math.random()就是获取0-1之间的随机数(永远获取不到1)
for(var i=0; i<10; i++){
var result= getRandom(10,100);
iArray.push(result);
}
iArray.sort();
52.把两个数组合并,并删除第二个元素。
考点:1、数组的concat、splice用法
splice() 方法删除数组的元素,或者向数组中添加元素,然后返回被删除的项目。
参数1:从何处开始删除数组的元素(使用负数则从数组的末尾开始)
参数2:要删除的元素个数(如果是0,就代表不删除)
参数3,4,5。。。:要添加的元素
var array1 = ['a','b','c'];
var bArray = [‘d’,’e’,’f’];
var cArray = array1.concat(bArray);
cArray.splice(1,1);
54.Javascript中, 以下哪条语句一定会产生运行错误? 答案( BC ) ??????????????
A、var _变量=NaN; //
B、var 0bj = []; // Invalid or unexpected token
C、var obj = //;
D、var obj = {};
//正确答案:BC
56.Javascript创建对象的几种方式?
构造函数方式,原型模式,混合构造函数原型模式,工厂方式,动态原型方式
混合构造函数+原型模式:
function Robot(name){
this.name=name;
}
Robot.prototype.say=function(){
alert("大家好,我叫"+this.name);
};
var alphaGo=new Robot("阿尔法狗");
alphaGo.say();
工厂方式:
function create(name,age){
var o={};
o.name=name;
o.age=age;
return o;
}
var p1=create("张三",20);
动态原型方式:
function Person(name,work){
this.name=name;
if(work){
Person.prototype.doWork=function(){
alert("我正在从事"+work+"的工作");
}
}
}
var p1=new Person("姚明");
var p2=new Person("喵喵","程序猿鼓励师");
59.documen.write和 innerHTML 的区别?
61.解释jsonp的原理,以及为什么不是真正的ajax
动态创建script标签,回调函数
Ajax是页面无刷新请求数据操作
62.将数字 12345678 转化成 RMB形式 如: 12,345,678
//思路:先将数字转为字符, str= str + ” ;
//利用反转函数,每三位字符加一个 ‘,’最后一位不加; re()是自定义的反转函数,最后再反转回去!
for(var i = 1; i <= re(str).length; i++){
tmp += re(str)[i - 1];
if(i % 3 == 0 && i != re(str).length){
tmp += ',';
}
}
64.什么是三元表达式 (Ternary expression)?“三元 (Ternary)” 表示什么意思?
一个运算符如果有一个操作数,为一元运算符,两个为二元,三个为三元运算符,三元表达式则为一个三元运算表达式!
71.如果某一个接口很缓慢,用户离开这个页面该怎么处理?
93.js有几种弹出窗
alert.confirm,prompt
find和filter的区别