深圳小鹅网络前端校招视频面试

文章目录

    • **2021.03.11 下午 深圳小鹅**
        • promise.all()方法有什么用
        • promise.then()的第二个参数是什么,具体实现了什么
          • Promise的then的第二个参数和catch的区别
        • es5的继承有哪些?
          • **原型链继承**
          • **借用构造函数**
          • **组合继承(原型链 + 借用构造函数)**
          • 原型式继承
          • ECMAScript5通过新增 Object.create()方法规范了原型式继承。
          • 用 Object.create实现类式继承
        • ES6中类、对象和继承
        • class继承中super有什么用 是干嘛的
        • call实现继承有什么缺点
        • 原型链和继承
        • BFC
        • **高度塌陷**
        • dart的基本数据类型
        • JavaScript的基本数据类型
        • 判断他的数据类型/数组的数据类型
        • 浏览器事件循环机制
          • 进程、线程
          • 浏览器内核
        • 状态码有哪些
        • vue的生命周期
        • 数组去重的方法 如果是对象怎么去重?
        • let 和 const 的 与var的区别是啥

2021.03.11 下午 深圳小鹅

promise.all()方法有什么用

Promise.all() 方法接收一个promise的iterable类型(Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例

输入的所有promise的resolve回调的结果是一个数组。这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。

它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。

Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例,一次性处理n个Promise对象。

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。

let p1 = new Promise((resolve, reject) => {
  resolve('成功了')
})

let p2 = new Promise((resolve, reject) => {
  resolve('success')
})

let p3 = Promse.reject('失败')

//p1和p2是两个Promise实例,包装成一个数组类型作为参数输入
Promise.all([p1, p2]).then((result) => {
  console.log(result)               //['成功了', 'success']
}).catch((error) => {
  console.log(error)
})
//只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数
Promise.all([p1,p3,p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error)      // 失败了,打出 '失败'
})

Promse.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。

注意:Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。

好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。

promise.then()的第二个参数是什么,具体实现了什么

1)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pcTUb3eQ-1617416519097)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615475364524.png)]

var p1 = new Promise((resolve,reject)=>{
	resolve();
	reject();
})
p1.then(()=>{
	console.log("then的第一个参数");
},()=>{
	console.log("then的第二个参数");
}).catch(()=>{
	console.log("catch输出");
})
//输出 then的第一个参数

如果then添加了第二个参数,这时候就不会执行catch里面的代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rfED0aOQ-1617416519102)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615475486540.png)]

var p2 = new Promise((resolve,reject)=>{
	reject();
	resolve();
})
p2.then(()=>{
	console.log("then的第一个参数");
},()=>{
	console.log("then的第二个参数");
}).catch(()=>{
	console.log("catch输出");
})
//输出 then的第二个参数

2)Promise中的then不添加第二个参数,这时候就会执行catch里面的代码

var p3 = new Promise((resolve,reject)=>{
	reject();
	resolve();
})
p3.then(()=>{
	console.log("then的参数");
}).catch(()=>{
	console.log("catch输出");
})
//输出 catch输出

3)Promise的链式结构原理是pro.then()或pro.catch()这个函数执行的返回值会返回一个promise对象,所以可以继续调用then或者catch,来完成链式结构。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ECtn8kkd-1617416519110)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615476173724.png)]

var pro=new Promise((resolve,reject)=>{
    resolve();
    reject();
})
pro.then(()=>{
    console.log('resolve1');
},()=>{console.log('reject1')}).catch(()=>{
    console.log('catch1')
}).then(()=>{
    console.log('resolve2');
},()=>{console.log('reject2')}).catch(()=>{
    console.log('catch2');
}).then(()=>{
    console.log('resolve3');
})
//输出resolve1 resolve2 resolve3

“promise执行完毕后返回的promise默认进入fulfilled状态”,所以执行完毕后默认执行链式结构中的resolve回调。

var pro=new Promise((resolve,reject)=>{
    // resolve();
    reject();
})
pro.then(()=>{
    console.log('resolve1');
},()=>{console.log('reject1')}).catch(()=>{
    console.log('catch1')
}).then(()=>{
    console.log('resolve2');
},()=>{console.log('reject2')}).catch(()=>{
    console.log('catch2');
}).then(()=>{
    console.log('resolve3');
})
//reject1 resolve2 resolve3

执行进入失败状态后,链式结构也会执行之后的resolve回调。

var pro=new Promise((resolve,reject)=>{
    resolve();
    reject();
})
pro.then(()=>{
    console.log('resolve1');
},()=>{console.log('reject1')).catch(()=>{
    console.log('catch1')
}).catch(()=>{
    console.log('catch2');
})
//输出结果 resolve1

如果不存在then,则也不会执行catch里面的代码,因为默认进入fullfilled状态。需要记住的点是,进入什么状态就会什么代码。

4)then里面的resolve报错,catch是可以捕获报错信息,then的第二个参数不能捕获,resolve的回调执行报错可以被catch捕获到

var pro=new Promise((resolve,reject)=>{
    resolve();
    reject();
})
pro.then(()=>{
    console.log('resolve1');
    var a = undefined;
    a.b();
    console.log('报错了的代码');
},(err)=>{console.log('reject1',err)}).catch((err)=>{
    console.log('catch1',err);
}).then(()=>{
    console.log('resolve2');
}).catch(()=>{
    console.log('catch2');
})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MaGOnfNU-1617416519114)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615476781052.png)]

Promise里面执行的代码可以被then的第二个参数捕获到,并且不会进入到resolve,而是直接进入reject

没有执行resolve代码,直接进入了reject

var pro=new Promise((resolve,reject)=>{
    var a = undefined;
    a.b();
    resolve();
    reject();
})
pro.then(()=>{
    console.log('resolve1');
    console.log('报错了的代码');
},(err)=>{console.log('reject1',err)}).catch((err)=>{
    console.log('catch1',err);
}).then(()=>{
    console.log('resolve2');
}).catch(()=>{
    console.log('catch2');
})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UITVihqG-1617416519120)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615476872970.png)]

就算没有reject回调,还是会进入reject回调

var pro=new Promise((resolve,reject)=>{
    var a = undefined;
    a.b();
    resolve();
    console.log('报错了的代码reject之前');
    // reject();
    console.log('报错了的代码reject之后');
})
pro.then(()=>{
    console.log('resolve1');
    console.log('报错了的代码');
},(err)=>{console.log('reject1',err)}).catch((err)=>{
    console.log('catch1',err);
}).then(()=>{
    console.log('resolve2');
}).catch(()=>{
    console.log('catch2');
})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-18I15rLj-1617416519125)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615477295509.png)]

如果不存在then的第二个回调,则会进入catch

var pro=new Promise((resolve,reject)=>{
    var a = undefined;
    a.b();
    resolve();
    console.log('报错了的代码reject之前');
    reject();
    console.log('报错了的代码reject之后');
})
pro.then(()=>{
    console.log('resolve1');
    console.log('报错了的代码');
}).catch((err)=>{
    console.log('catch1',err);
}).then(()=>{
    console.log('resolve2');
}).catch(()=>{
    console.log('catch2');
})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4XEAlexn-1617416519129)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615477435538.png)]

如果catch的执行过程中报错,则进入之后相邻的catch

Promise的then的第二个参数和catch的区别

reject是用来抛出异常的,catch是用来处理异常的;
reject是Promise的方法,而then和catch是Promise实例的方法(Promise.prototype.then 和 Promise.prototype.catch)。

如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到。

then的第二个参数和catch捕获错误信息的时候会就近原则,如果是promise内部报错,reject抛出错误后,then的第二个参数和catch方法都存在的情况下,只有then的第二个参数能捕获到,如果then的第二个参数不存在,则catch方法会捕获到。

es5的继承有哪些?

原型链继承

原型链继承的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。

function People() {
    this.name = 'sophia';
    this.hobbies=['swimming', 'skiing']
}

People.prototype.getName = function () {
    return this.name;
};
function Man() {
    this.sex = 'male'
}

Man.prototype = new People();
Man.prototype.getSex = function(){
    return this.sex
}
Man.prototype.constructor = Man;
let person1 = new Man();
person1.hobbies.push('basketball')
console.log(1101, person1)
console.log(11, person1.getName()) //"sophia"
console.log(22, person1.hobbies) // ["swimming", "skiing", "basketball"]

let person2 = new Man();
person1.hobbies.push('football')
console.log(22, person2.hobbies)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-krKKnw7a-1617416519132)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615515939068.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9lORlRpF-1617416519138)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615515958953.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7EgNeeiD-1617416519144)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615516013066.png)]

缺点:
1. 通过原型来实现继承时,原型会变成另一个类型的实例,原先的实例属性变成了现在的原型属性,该原型的引用类型属性会被所有的实例共享。
2. 在创建子类型的实例时,没有办法在不影响所有对象实例的情况下给超类型的构造函数中传递参数。
借用构造函数

基本思想为: 在子类型的构造函数中调用超类型构造函数。

function People(name) {
    this.name = name;
    this.hobbies=['swimming', 'skiing']
}

function Man(name) {
    People.call(this, name)
    this.sex = 'male'
}
let person1 = new Man('sophia');
person1.hobbies.push('basketball')
console.log(11, person1.name)    //sophia
console.log(22, person1.hobbies)    //['swimming', 'skiing','basketball']

let person2 = new Man('jack')
person2.hobbies.push('football')
console.log(33, person2.name)   //jack
console.log(44, person2.hobbies)     //['swimming', 'skiing','football']

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KWnxIaQC-1617416519151)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615516258256.png)]

优点:可以向超类传递参数,解决了原型中包含引用类型值被所有实例共享的问题
缺点: 方法都在构造函数中定义,函数复用无从谈起,另外超类型原型中定义的方法对于子类型而言都是不可见的。
组合继承(原型链 + 借用构造函数)

基本思路:使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承,既通过在原型上定义方法来实现了函数复用,又保证了每个实例都有自己的属性。

function People(name) {
    this.name = name;
    this.hobbies=['swimming', 'skiing']
}

People.prototype.getName = function () {
    return this.name;
};
function Man(name) {
    People.call(this, name)
    this.sex = 'male'
}

Man.prototype = new People();
Man.prototype.getSex = function(){
    return this.sex
}
Man.prototype.constructor = Man;
let person1 = new Man('lily');
person1.hobbies.push('basket')

console.log(11, person1.getName()) //"lily"
console.log(22, person1.hobbies) // ["swimming", "skiing", "basket"]
let person2 = new Man('lucy');
person2.hobbies.push('foot')
console.log(33, person2.getName()) // "lucy"
console.log(44, person2.hobbies) //["swimming", "skiing", "foot"]
缺点:无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。
优点:可以向超类传递参数,每个实例都有自己的属性,实现了函数复用
原型式继承

借助原型并基于已有的对象创建新对象,同时还不用创建自定义类型的方式称为原型式继承。

function createObj(o) {
  console.log(11, o)
  function F() { }
  F.prototype = o;
  console.log(22, F)
  return new F();
} //在 createObj() 函数内部,先创建一个临时性的构造函数F,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例,从本质上讲,createObj() 对传入的对象执行了一次浅拷贝。

let parent = {
  name: 'lily',
  arr: ['hello', 'world']
};
var child1 = createObj(parent);
child1.arr.push('apple1')
console.log('----->', child1)
console.log('------>', child1.name, '----->', child1.arr)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vXKKVgl9-1617416519153)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615516955303.png)]

let child2 = createObj(parent);
child2.arr.push('banana')
console.log('------>', child2.name, '----->', child2.arr)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-larIPhN0-1617416519158)(C:\Users\windows\AppData\Roaming\Typora\typora-user-images\1615517050054.png)]

缺点同原型链实现继承一样,包含引用类型值的属性会被所有实例共享 
ECMAScript5通过新增 Object.create()方法规范了原型式继承。
Object.create( proto [, propertiesObject] )
这个方法接收两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象(可以覆盖原型对象上的同名属性),在传入一个参数的情况下,Object.create() 和 object() 方法的行为相同。
const person = {
  isHuman: false,
  printIntroduction: function () {
    console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  }
};

const me = Object.create(person);

me.name = "Matthew"; // "name" is a property set on "me", but not on "person"
me.isHuman = true; // inherited properties can be overwritten

me.printIntroduction();
// 输出  "My name is Matthew. Am I human? true"
用 Object.create实现类式继承
// Shape - 父类(superclass)
function Shape() {
  this.x = 0;
  this.y = 0;
}

// 父类的方法
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.');
};

// Rectangle - 子类(subclass)
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?',
  rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
  rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'

继承到多个对象,则可以使用混入的方式Object.assign。

function MyClass() {
     SuperClass.call(this);
     OtherSuperClass.call(this);
}

// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;

MyClass.prototype.myMethod = function() {
     // do a thing
};

使用 Object.create 的 第二个参数是propertyObject

o = Object.create(Object.prototype, {
  // foo会成为所创建对象的数据属性
  foo: { 
    writable:true,
    configurable:true,
    value: "hello" 
  },
  // bar会成为所创建对象的访问器属性
  bar: {
    configurable: false,
    get: function() { return 10 },
    set: function(value) {
      console.log("Setting `o.bar` to", value);
    }
  }
});

ES6中类、对象和继承

es6的继承又有哪些

有新的关键字class用于声明这是一个类,新的关键字constructor用于声明构造函数,新的关键字static用于声明静态方法。静态属性的话,同样是不能写在类里面,要写在外面,而且同样静态属性和静态方法不能被实例化对象所调用,只能被类所调用。

class People {
  constructor(name, age) {
    this.name = name
    this.age = age
  }

  showName() {
    console.log('我的名字是' + this.name)
  }

  // 静态方法
  static getCount() {
    console.log('当前共有' + People.count + '个人')
  } 
}

People.count = 1
let xiaoming = new People('xiaoming', 22)
xiaoming.showName()

在ES6中引入了两个新的关键字来实现继承,分别是extends用来继承父类的方法,和super用来让子类继承父类中构造函数的属性。

class继承中super有什么用 是干嘛的

继承用extends,当继承后需要用super()来接收父类的constructor构造函数,否则报错,当new一个子类的时候先把参数传入子类构造函数再通过super()将父类的构造函数引入,就可以调用父类。

class Animal {
  constructor(name) {
    this.name = name
  }

  showName() {
    console.log('名字是:' + this.name)
  }
}

class Dog extends Animal{
  constructor(name, color) {
    super(name)
    this.color = color
  }

  showColor() {
    console.log('颜色是' + this.color)
  }
}

let xiaohua = new Dog('xiaohua', 'white')
xiaohua.showName()
xiaohua.showColor()

call实现继承有什么缺点

// 父类
function Animal(name) {
    this.name = name
}
Animal.prototype.showName = function () {
  console.log('名字是:' + this.name)
}

// 子类
function Dog(name, color) {
    // call的作用是用于改变this指向,传入得第一个参数用于表示指向谁
    // 这里用于指向Dog(传入得是指向Dog的this)
    // 第二个参数是Anmial中所对应的参数
    Animal.call(this, name) // 继承属性

    // 自己个性化的属性
    this.color = color
}

// 原型继承
Dog.prototype = new Animal()
Dog.prototype.constuctor = Dog

let d1 = new Dog('wangcai', 'white')
d1.showName()

原型链和继承

var p1 = new Person()

Person()构造函数有一个独有的属性是prototype指向Person.prototype这个实例原型

Person.prototype有一个constructor属性指回Person()

p1的_proto_指向Person.prototype,从对象指向实例

Person.prototype也有_proto_指向Object.prototype这一原型

Object也有prototype指向Object.prototype,反之Object.prototype有constructor指回Object

Object.prototype_proto_指向null

使用不同的方法来创建对象和生成原型链

语法结构创建的对象

var o = { a: 1 };这是一个定义对象的语法,这个语句使对象o继承了Object.prototype上所有的属性,o本身没有名为hasOwenProperty的属性,hasOwnProperty是Object.property的属性,因此对象o继承了Object.prototype的hasOwnProperty属性方法。Object.property的原型为null,原型链如下:o -> Object.prototype -> null
var a = ["yo", "whadup", "?"]; 这是一个定义数组的语法,数组都继承于Array.prototype,Array.prototype中包含indexOf,forEach等方法,原型链如下:a -> Array.prototype -> Object.prototype -> null
function f() = { return 2; } 这是一个定义函数的语法,函数都继承于Function.prototype,Function.prototype中包含call,bind等方法,原型链如下:f -> Function.prototype -> Object.prototype -> null

使用构造器创建的对象

在JavaScript中,构造器(构造方法)其实就是一个普通的函数。当使用new操作符来作用这个函数时,它就可以被称为成为构造方法或者构造函数。

function Graph() {
        this.vertices = []
        this.edges = []
    }

    Graph.prototype = {
        addVertice: function (v) {
            this.vertices.push(v);
        }
    }
    var g = new Graph();
    console.log(g);

g是使用构造方法new Graph()生成的对象,它有自己的属性vertices和edges,还有从自己的原型对象中继承的addVertice方法,在g被实例化时,g._proto_指向了Graph.prototype

Object.create创建的对象

ES5方法Object.create()

可以调用这个方法来创建一个新对象。新对象的原型就是调用create方法时传入的第一个参数。

var a = {a: 1};  //定义对象a,它有属性a
var b = Object.create(a);  //使用Object.Create(a)创建对象b,b的原型是a
console.log(b.a);  //输出b.a,在对象b上查找属性a,没有,后在b的原型a上找,值是1

var c = Object.create(b); //使用Object.Create(b)创建对象c,c的原型是b
console.log(c);  //输出对象c,它的原型的原型上有一个属性c,值为1
console.log(c.a);  //输出c.a,现在对象c的属性中查找a,没有,在c的原型b上查找属性a,没有,在b的原型a上查找属性a,有,值为1,输出1

var d = Object.create(null);  //使用Object.Create(null)创建对象d,**注意null没有原型
console.log(d.hasOwnProperty); //输出d.hasOwnProperty方法,在d的方法中找,没有,在d的原型null中找,也没有,最后输出undefined

class关键字创建对象

class Polygon {
        constructor(height, width) {
            this.width = width;
            this.height = height;
        }
    }

    class Square extends Polygon {
        constructor(sideLength) {
            super(sideLength, sideLength);
        }

        get area() {
            return this.height * this.width;
        }

        set sideLength(sideLength) {
            this.height = sideLength;
            this.width = sideLength;
        }
    }

    var square = new Square(2);
    writeStr(square.area);   //4

BFC

BFC是什么?有什么用?怎么产生?解决了什么问题?实际遇到过的问题

BFC(block formatting context):简单来说,BFC 就是一种属性,这种属性会影响着元素的定位以及与其兄弟元素之间的相互作用。
中文常译为块级格式化上下文。是W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。
在进行盒子元素布局的时候,BFC提供了一个环境,在这个环境中按照一定规则进行布局不会影响到其它环境中的布局。比如浮动元素会形成BFC,浮动元素内部子元素的主要受该浮动元素影响,两个浮动元素之间是互不影响的。 也就是说,如果一个元素符合了成为BFC的条件,该元素内部元素的布局和定位就和外部元素互不影响(除非内部的盒子建立了新的 BFC),是一个隔离了的独立容器。(在 CSS3 中,BFC 叫做 Flow Root)

形成 BFC 的条件

1、浮动元素,float 除 none 以外的值;
2、绝对定位元素,position(absolute,fixed);
3、display 为以下其中之一的值 inline-blocks,table-cells,table-captions;
4、overflow 除了 visible 以外的值(hidden,auto,scroll)

创建 BFC 的方式有:

1.html的根元素

2.float浮动

3.绝对定位

4.overflow不为 visible

5.display为表格布局或弹性布局

6.contain值为layout

7.content或 strict的元素等。

BFC常见作用

1.清除浮动

2.解决margin塌陷问题

BFC的特点:

1.内部box会一个一个的垂直放置

2.形成了BFC的区域不会与float box重叠,BFC在页面是个独立的容器,里外元素互不影响

3.BFC在计算高度时会把浮动元素计算进去

4.在BFC中,每一个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)(对于从右到左的格式来说,则触碰到右边缘)

高度塌陷

父元素在文档流中高度默认是被子元素撑开的,当子元素脱离文档流以后,将无法撑起父元素的高度,也就会导致父元素的高度塌陷。父元素的高度一旦塌陷, 所有标准流中元素的位置将会上移,导致整个页面的布局混乱
解决方法:
(1)浮动元素后添加清除浮动样式,使用这种方式会在页面中添加多余的结构。

.clear{
clear:both
}

(2)使用after伪类,向父元素后添加一个块元素,并对其清除浮动。该种方式的原理和方法一原理一样,但是不用向页面中添加多余的结构。

#div::after {
content: “”;
display: block;
clear: both
}

(3)开启父元素的BFC,为父元素添加样式

overflow:hidden;

(4)手动为父元素添加高度。

dart的基本数据类型

Number、String、Boolean、List(也可称为Array)、Map、Set、Rune(用于在字符串中表示 Unicode 字符)、Symbol

JavaScript的基本数据类型

【基本类型 5】string、number(浮点数,整数,NAN)、boolean、null、undefined
【引用类型 1】object(data,function,array)
【es6 1】symbol
【bigInt】Javascript 中的任意精度整数,可以安全存储和操作大整数。即始超出 Number 能够表示的安全整数范围。是 chrome 67中的新功能。

判断他的数据类型/数组的数据类型

typeof

  • 用来判断数据类型,返回值为6个字符串,分别是string, boolean, number, function, object, undefined
  • typeof在判断null、Array、Object以及(new + 函数)时,得到的都是object,这个时候就要用instanceof了

instanceof

  • 用来判断数据类型, obj1 instanceof obj2 返回true或者false
  • str instanceof String
  • n instanceof Number/Boolean/Object/Date/Array

直接的字面量值判断数据类型,只有引用数据类型(Array,Function,Object)被精准判断,其他(数值Number,布尔值Boolean,字符串String)字面值不能被instanceof精准判断。

instanceof 在MDN中的解释:instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。其意思就是判断对象是否是某一数据类型(如Array)的实例,请重点关注一下是判断一个对象是否是数据类型的实例。(字面量值,2, true ,'str’不是实例,所以判断值为false)

constructor

console.log((2).constructor === Number);   //true 
console.log((true).constructor === Boolean);      //true 
console.log(('str').constructor === String);     //true 
console.log(([]).constructor === Array);     //true 
console.log((function() {}).constructor === Function);    //true 
console.log(({}).constructor === Object);    //true 

如果我创建一个对象,更改它的原型,这种方式也变得不可靠了

    function Fn(){}; 
    Fn.prototype=new Array();    
    var f=new Fn();     
    console.log(f.constructor===Fn);    // false
    console.log(f.constructor===Array); // true 

万能 Object.prototype.toString.call

使用 Object 对象的原型方法 toString ,使用 call 进行狸猫换太子,借用Object的 toString 方法

class Person{
constructor(name){
        this.name = name;
      }
    }

    let a1 = null;
    let a2;
    let a3 = function(){};
    let a4 = new Object();
    let a5 = new Person("person");

    console.log(Object.prototype.toString.call(a1));   // [object Null]
    console.log(Object.prototype.toString.call(a2));   // [object Undefined]
    console.log(Object.prototype.toString.call(a3));   // [object Function]
    console.log(Object.prototype.toString.call(a4));   // [object Object]
    console.log(Object.prototype.toString.call(a5));   // [object Object]

浏览器事件循环机制

进程、线程
  • 进程是系统分配的独立资源,是 CPU 资源分配的基本单位,进程是由一个或者多个线程组成的。
  • 线程是进程的执行流,是CPU调度和分派的基本单位,同个进程之中的多个线程之间是共享该进程的资源的。
浏览器内核
  • 浏览器是多进程的,浏览器每一个 tab 标签都代表一个独立的进程(也不一定,因为多个空白 tab 标签会合并成一个进程),浏览器内核(浏览器渲染进程)属于浏览器多进程中的一种。
  • 浏览器内核有多种线程在工作。
    • GUI 渲染线程:
      • 负责渲染页面,解析 HTML,CSS 构成 DOM 树等,当页面重绘或者由于某种操作引起回流都会调起该线程。
      • 和 JS 引擎线程是互斥的,当 JS 引擎线程在工作的时候,GUI 渲染线程会被挂起,GUI 更新被放入在 JS 任务队列中,等待 JS 引擎线程空闲的时候继续执行。
    • JS 引擎线程:
      • 单线程工作,负责解析运行 JavaScript 脚本。
      • 和 GUI 渲染线程互斥,JS 运行耗时过长就会导致页面阻塞。
    • 事件触发线程:
      • 当事件符合触发条件被触发时,该线程会把对应的事件回调函数添加到任务队列的队尾,等待 JS 引擎处理。
    • 定时器触发线程:
      • 浏览器定时计数器并不是由 JS 引擎计数的,阻塞会导致计时不准确。
      • 开启定时器触发线程来计时并触发计时,计时完成后会被添加到任务队列中,等待 JS 引擎处理。
    • http 请求线程:
      • http 请求的时候会开启一条请求线程。
      • 请求完成有结果了之后,将请求的回调函数添加到任务队列中,等待 JS 引擎处理。

状态码有哪些

200——请求成功

204——请求成功但是没有返回数据

301——永久重定向

302——临时重定向

304是怎么产生的——当请求时,页面没有修改

400——请求报文语法错误

404——请求资源不存在

401——需要认证

403——认证失败

500——请求失败

503——错误网关

vue的生命周期

beforeCreated、created、beforeMounted、mounted、beforeDistory、distory

数组去重的方法 如果是对象怎么去重?

set集合方法

indexOf

includes

webpack的打包原理

let 和 const 的 与var的区别是啥

var 是定义的全局变量会挂载到window上

let会形成块级作用域

const定义的变量是个常量值不能改

}
}

let a1 = null;
let a2;
let a3 = function(){};
let a4 = new Object();
let a5 = new Person("person");

console.log(Object.prototype.toString.call(a1));   // [object Null]
console.log(Object.prototype.toString.call(a2));   // [object Undefined]
console.log(Object.prototype.toString.call(a3));   // [object Function]
console.log(Object.prototype.toString.call(a4));   // [object Object]
console.log(Object.prototype.toString.call(a5));   // [object Object]



#### 浏览器事件循环机制

##### 进程、线程

- 进程是系统分配的独立资源,是 CPU 资源分配的基本单位,进程是由一个或者多个线程组成的。
- 线程是进程的执行流,是CPU调度和分派的基本单位,同个进程之中的多个线程之间是共享该进程的资源的。

##### 浏览器内核

- 浏览器是多进程的,浏览器每一个 tab 标签都代表一个独立的进程(也不一定,因为多个空白 tab 标签会合并成一个进程),浏览器内核(浏览器渲染进程)属于浏览器多进程中的一种。
- 浏览器内核有多种线程在工作。
  - GUI 渲染线程:
    - 负责渲染页面,解析 HTML,CSS 构成 DOM 树等,当页面重绘或者由于某种操作引起回流都会调起该线程。
    - 和 JS 引擎线程是互斥的,当 JS 引擎线程在工作的时候,GUI 渲染线程会被挂起,GUI 更新被放入在 JS 任务队列中,等待 JS 引擎线程空闲的时候继续执行。
  - JS 引擎线程:
    - 单线程工作,负责解析运行 JavaScript 脚本。
    - 和 GUI 渲染线程互斥,JS 运行耗时过长就会导致页面阻塞。
  - 事件触发线程:
    - 当事件符合触发条件被触发时,该线程会把对应的事件回调函数添加到任务队列的队尾,等待 JS 引擎处理。
  - 定时器触发线程:
    - 浏览器定时计数器并不是由 JS 引擎计数的,阻塞会导致计时不准确。
    - 开启定时器触发线程来计时并触发计时,计时完成后会被添加到任务队列中,等待 JS 引擎处理。
  - http 请求线程:
    - http 请求的时候会开启一条请求线程。
    - 请求完成有结果了之后,将请求的回调函数添加到任务队列中,等待 JS 引擎处理。

#### 状态码有哪些

200——请求成功

204——请求成功但是没有返回数据

301——永久重定向

302——临时重定向

304是怎么产生的——当请求时,页面没有修改

400——请求报文语法错误

404——请求资源不存在

401——需要认证

403——认证失败

500——请求失败

503——错误网关

#### vue的生命周期

beforeCreated、created、beforeMounted、mounted、beforeDistory、distory



#### 数组去重的方法 如果是对象怎么去重?

**set集合方法**

**indexOf**

**includes**



webpack的打包原理

#### let 和 const 的 与var的区别是啥

var 是定义的全局变量会挂载到window上

let会形成块级作用域

const定义的变量是个常量值不能改

你可能感兴趣的:(2021前端校招,前端面试,javascript,vue.js,html,面试)