前段时间为了面试,我也是猛刷了许多的面经,自己也总结了一些,决定写成博客,既能重新复习一下,又能和大家分享。
1、继承的几种方式(优缺点)
1)ES6中的class
class A{
constructor(name,age){
this.name = name;
this.age = age;
}
sayHello(){
console.log("Hello "+this.name);
}
}
class B extends A{ // B继承A
constructor(name,age,major,){
super(name,age);
this.major = major;
}
}
let b = new B('EmailyT',23,'计算机');
b.sayHello() //Hello EmailyT
2)原型链方式继承
function fn() {
this.name = 'EmailyT';
this.age = 23;
}
fn.prototype.sex = 'female';
function fn1() {
this.major = "计算机科学与技术";
}
fn1.prototype = new fn();
let f = new fn1();
console.log(f.name)
缺点:
①、不能向父类传参数
②、原型继承,会引发原型共享的问题(改动原型上内容)一处更改,其他也会变
3)借用构造函数
function fn(name,age) {
this.name = name;
this.age = age;
}
function fn1(name,age,major) {
fn.call(this,name,age);
this.major = major;
}
let f = new fn1('EmailyT',23,'计算机');
console.log(f.name,f.age,f.major) // EmailyT 23 计算机
优点:可以解决原型继承无法传参的问题
缺点:每个子类继承时都会创建一个,无法实现函数复用
4)组合继承(原型+构造)
function fn(name,age) {
this.name = name;
this.age = age;
}
+ fn.prototype.sex = 'female';
function fn1(name,age,major) {
fn.call(this,name,age); ②
this.major = major;
}
+ fn1.prototype = new fn(); ① //如果这行不写的话,就不会得到 'sex'
+ fn1.prototype.constructor = fn1;
let f = new fn1('EmailyT',23,'计算机');
console.log(f.sex) //female
优点:既可以传参数,又可以继承原型上的内容
缺点:两次调用了父类(标注的地方)
5)寄生式继承
function createfn(origin) {
let obj = Object(origin); //创建时需要传入一个父类,复制一份
obj.sayHi = function () { //自己拥有的方法
console.log('Hi')
};
return obj;
}
let parent = {
name:"EamilyT",
age:23,
};
let child = new createfn(parent);
console.log(child.name)
6)寄生组合式继承
function createfn(child,parent) {
let obj = Object(parent.prototype); //创建副本subP.prototype=parent.prototype
obj.constructor = child; //改变指向
child.prototype = obj;
}
function sub(names,age) {
this.names = names;
this.age = age;
}
sub.prototype.sex = 'female';
function superP(names,age) {
sub.call(this,names,age);
}
createfn(superP,sub);
let c = new superP('EmailyT',23);
console.log(c.names,c.sex); //也可以继承原型属性
2、扁平化数组
let arr = [1,2,[3,[4,5],6],[7,8],9]; //全局数组
1、使用flat()
arr = arr.flat(4) //参数是数组嵌套的层数
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
如果嵌套的层数过多,可以传一个值:arr.flat(Infinity)
2、使用concat连接数组(循环判断)
let res = []; //创建新数组
function flat(arr) {
for (let i = 0;i<arr.length;i++){
if (Array.isArray(arr[i])){ //循环判断当前元素是不是数组
res.concat(flat(arr[i]));
}else{
res.push(arr[i]) //不是则添加
}
}
return res;
}
3、使用toString+split
function flat(arr) {
return arr.toString().split(',').map(function(item) {
return Number(item);
})
}
3、js的事件模型
1)DOM0级事件:是将事件直接绑定到元素上,比如:
<button "handle()" id="btn">按钮</button>
//js
function handle(){ //绑定
//...
}
//移除事件:element.onclick = null
DOM0级事件的好处是兼容所有的浏览器,但是没有事件流(冒泡、捕获)
2)DOM1级事件:通过addEventListener()添加,比如:
let btn = document.getElementById('btn');
btn.addEventListener('click',function(){
//...
},false)
//移除事件监听:removeEventListener
DOM1级事件有三个阶段:事件捕获、事件处理、事件冒泡
3)IE事件:通过attachEvent()添加
let btn = document.getElementById('btn');
btn.attachEvent('onClick',fu) //这里是“onclick”和DOM2级不一样
//移除事件监听
btn.detachEvent()
IE只有事件捕获这事件冒泡阶段
4、new的过程(以及实现)
- 首先会创建一个新的对象
- 将新创建的对象的_proto_指向构造函数的原型
- 为this对象添加属性和方法
- return 对象
代码实现:
function new(fn){
let obj = {};
obj._proto_ = fn.prototype;
let res = fn.call(obj);
if(typeof res =='object' || typeof res == 'function'){
return res;
}
return obj;
}
5、BFC以及形成的原因(和效果)
BFC:块级格式化上下文
有什么效果:
- BFC元素垂直方向依次排列,上下两个元素边距会发生重叠
- 可以用来清楚浮动
- BFC是个独立的区域,块内的子元素不会影响外面的内容,反之亦然
- BFC区域并不会和float元素重叠
形成的因素:
- overflow的值不为visibility
- float元素
- 定位元素position的值为absolute、fixed
- display的值为inline-block、flex、table-cell…
垂直方向元素的margin重叠问题:
- 值都为正情况:取最大值
- 值都为负情况:取绝对值之后的最大值
- 值一正一负情况:两者相加之后的值
6、箭头函数和普通函数的区别
1、箭头函数的this指向规则
大家都知道箭头函数中没有this,this指向的是箭头函数外的第一个普通函数,那么为什么箭头函数没有this呢?因为箭头函数没有原型 prototype,so
let a = ()=>{return 1};
console.log(a.prototype) //打印undefined
刚才也说了,箭头函数中的this是指向外层的普通函数,并且也不能改变箭头函数中的this,只能改变外层的普通函数的this指向,那么来测试看看吧!
var obj = {
t:function(){
console.log(this)
},
ac:function(){
setTimeout(()=>{
console.log(this)
},100)
}
}
obj.t(); //{t: ƒ, ac: ƒ}
obj.ac() //{t: ƒ, ac: ƒ}
在严格模式下还是非严格模式下如果箭头函数外边没有普通函数,那么this都指向window
2、arguments的使用问题
我们已经了解到,箭头函数中没有this,那么肯定也没有自己的arguments,但是它可以使用外层函数的arguments。
//箭头函数没有自己的arguments,想不报错的话,可以声明一个变量
let fn = ()=>{
console.log(arguments)
}
fn(1,2) //arguments is not defined
function bar() {
console.log(arguments); // ['外层第二个普通函数的参数']
bb('外层第一个普通函数的参数');
function bb() {
console.log(arguments); // ["外层第一个普通函数的参数"]
let a = () => {
console.log(arguments); // ["外层第一个普通函数的参数"] this继承外层的普通函数
};
a('箭头函数的参数'); // this指向bb
}
}
bar('外层第二个普通函数的参数');
3、箭头函数不支持new、不支持参数重名
let a = ()=>{ }
let c = new a() // a is not a constructor
//另外,箭头函数没有原型,同时也没有constructor
//参数问题
let a = (c,c)=>{
console.log(c) //报错,Duplicate parameter name not allowed in this context
}
a(1,2)
以上是箭头函数的一些特性,这有更全的?博客,大家可以看看,总结的挺全。
7、不借助辅助空间情况下,找出不重复的元素
let arr = [0,0,1,1,1,2,3,4,5,5];
let i = 0,j=0;
for(i = 0;i<arr.length;i++){
for(j = 0;j<arr.length;j++){
if(arr[i]==arr[j] && i!=j){ //自身不和自身比较
break; //一旦相同,立即退出
}
}
if(j==arr.length) console.log(arr[i]) //如果相等,说明没有重复的元素,输出即可
}
//结果为:2,3,5
这是我目前想出来的一种,欢迎大家补充其他高效的方法。
这次呢,就先分享这些,等到下篇博客我会继续为大家分享。有意见不同的地方,欢迎大家留言讨论。