大前端面试梳理

2次阅读

共计 4997 个字符,预计需要花费 13 分钟才能阅读完成。

HTML
CSS
Javascript
JS 基本介绍

JS 的用途:Javascript 可以实现浏览器端、服务器端(nodejs)。。。

浏览器端 JS 由以下三个部分组成:

ECMAScript:基础语法(数据类型、运算符、函数。。。)
BOM(浏览器对象模型):window、location、history、navigator。。。
DOM(文档对象模型):div、p、span。。。

ECMAScript 又名 es,有以下重大版本:

旧时代:
es1.0。。。es3.1

新时代:

es5
es6(es2015)
es7(es2016)、es8(es2017)

数据类型

基本数据类型——值类型:(数字、字符串、布尔值、null、undefined)
undefined 类型?

复杂数据类型——引用类型:(对象)

数组
函数
正则表达式
Date

对象的基本使用
创建一个对象
var student={
name:” 李白 ” , //student 有一个 name 属性,值为 ” 李白 ”
grade:” 初一 ” ,
//a、student 有一个 say 属性,值为一个函数
//b、student 有一个 say 方法
say:function(){
console.log(“ 你好 ”);
},
run:function(speed){
console.log(“ 正在以 ”+speed+” 米 / 秒的速度奔跑 ”);
}
}
对象是键值对的集合:对象是由属性和方法构成的 (ps:也有说法为:对象里面皆属性,认为方法也是一个属性)

name 是属性 grade 是属性
say 是方法 run 是方法

对象属性操作
获取属性:
第一种方式:. 语法

student.name 获取到 name 属性的值,为:” 李白 ”
student.say 获取到一个函数

第二种方式:[]语法

student[“name”] 等价于 student.name
student[“say”] 等价于 student.say

2 种方式的差异:

. 语法更方便,但是坑比较多(有局限性),比如:

. 后面不能使用 js 中的关键字、保留字(class、this、function。。。)
. 后面不能使用数字

var obj={};
obj.this=5; // 语法错误
obj.0=10; // 语法错误

[]使用更广泛

o1[变量 name]
[“class”]、[“this”]都可以随意使用 obj[“this”]=10

[0]、[1]、[2]也可以使用

obj[3]=50 = obj[“3”]=50
思考:为什么 obj[3]=obj[“3”]

甚至还可以这样用:[“[object Array]”]
jquery 里面就有这样的实现

也可以这样用:[“{abc}”]
给对象添加了 {abc} 属性

设置属性

student[“gender”]=” 男 ” 等价于:student.gender=” 男 ”

含义:如果 student 对象中没有 gender 属性,就添加一个 gender 属性,值为 ” 男 ”
如果 student 对象中有 gender 属性,就修改 gender 属性的值为 ” 男 ”

案例 1:student.isFemale=true

案例 2:student[“children”]=[1,2,5]

案例 3:

student.toShanghai=function(){
console.log(“ 正在去往上海的路上 ”)
}
删除属性

delete student[“gender”]
delete student.gender

通过构造函数创建对象
构造函数创建对象的例子:

var xiaoming = new Object() –> var xiaoming = {};
var now = new Date()
var rooms = new Array(1,3,5) –> var rooms = [1,3,5]

var isMale=/123/; ==> var isMale=new RegExp(“123”)

isMale 是通过 RegExp 构造函数创建出来的对象
isMale 是 RegExp 构造函数的实例

以上例子中,Object、Date、Array 都是内置的构造函数

自定义一个构造函数来创建对象
构造函数
function Person(name,age){
this.name=name;
this.age=age;
}
var p1=new Person(“ 赵云 ”,18)
说明:p1 就是根据【Person 构造函数】创建出来的对象

构造函数的概念

任何函数都可以当成构造函数 function CreateFunc(){}

只要把一个函数通过 new 的方式来进行调用,我们就把这一次函数的调用方式称之为:构造函数的调用

new CreateFunc(); 此时 CreateFunc 就是一个构造函数
CreateFunc(); 此时的 CreateFunc 并不是构造函数

关于 new Object()
new Object()等同于对象字面量{}
构造函数的执行过程
var p1=new Person();

1、创建一个对象 (我们把这个对象称之为 Person 构造函数的实例)- _p1

2、创建一个内部对象,this,将 this 指向该实例(_p1)
3、执行函数内部的代码,其中,操作 this 的部分就是操作了该实例(_p1)

4、返回值:

a、如果函数没有返回值(没有 return 语句),那么就会返回构造函数的实例(p1)
b、如果函数返回了一个基本数据类型的值,那么本次构造函数的返回值是该实例(_p1)

function fn(){

}
var f1=new fn(); //f1 就是 fn 的实例

function fn2(){
return “abc”;
}
var f2=new fn2(); //f2 是 fn2 构造函数的实例
c、如果函数返回了一个复杂数据类型的值,那么本次函数的返回值就是该值
function fn3(){
return [1,3,5];
// 数组是一个对象类型的值,
// 所以数组是一个复杂数据类型的值
//–> 本次构造函数的真正返回值就是该数组
//–> 不再是 fn3 构造函数的实例
}
var f3=new fn3(); //f3 还是 fn3 的实例吗?错
//f3 值为[1,3,5]

继承
JS 中继承的概念:
通过【某种方式】让一个对象可以访问到另一个对象中的属性和方法,我们把这种方式称之为继承 并不是所谓的 xxx extends yyy

为什么要使用继承?
有些对象会有方法(动作、行为),而这些方法都是函数,如果把这些方法和函数都放在构造函数中声明就会导致内存的浪费
function Person(){
this.say=function(){
console.log(“ 你好 ”)
}
}
var p1=new Person();
var p2=new Person();
console.log(p1.say === p2.say); //false
继承的第一种方式:原型链继承 1
Person.prototype.say=function(){
console.log(“ 你好 ”)
}
缺点:添加 1、2 个方法无所谓,但是如果方法很多会导致过多的代码冗余
继承的第二种方式:原型链继承 2
Person.prototype={
constructor:Person,
say:function(){
console.log(“ 你好 ”);
},
run:function(){
console.log(“ 正在进行百米冲刺 ”);
}
}

注意点:
a、一般情况下,应该先改变原型对象,再创建对象
b、一般情况下,对于新原型,会添加一个 constructor 属性,从而不破坏原有的原型对象的结构

继承的第三种方式:拷贝继承(混入继承)

场景:有时候想使用某个对象中的属性,但是又不能直接修改它,于是就可以创建一个该对象的拷贝
实现 1:

var source={name:” 李白 ”,age:15}
var target={};
target.name=source.name
target.age=source.age;
上面的方式很明显无法重用,实际代码编写过程中,很多时候都会使用拷贝继承的方式,所以为了重用,可以编写一个函数把他们封装起来:
function extend(target,source){
for(key in source){
target[key]=source[key];
}
return target;
}
extend(target,source)

由于拷贝继承在实际开发中使用场景非常多,所以很多库都对此有了实现
jquery:$.extend

es6 中有了对象扩展运算符仿佛就是专门为了拷贝继承而生:

var source={name:” 李白 ”,age:15}
var target={…source}
继承的第四种方式:原型式继承

场景:

创建一个纯洁的对象
创建一个继承自某个父对象的子对象

使用方式:

空对象:Object.create(null)

var o1={say:function(){}}
var o2=Object.create(o1);

继承的第五种方式:借用构造函数实现继承
场景:适用于 2 种构造函数之间逻辑有相似的情况
function Animal(name){
this.name=name;
}function Person(name,age){
this.name=name;
this.age=age;
}
以上代码用借用构造函数实现
function Animal(name,age){
this.name=name;
this.age=age;
}
function Person(name,age,address){
Animal.call(this,name);
//this.name=name;
//this.age=age;
this.address=address;
}
原型链
闭包
变量作用域

变量作用域的概念:就是一个变量可以使用的范围
JS 中首先有一个最外层的作用域:称之为全局作用域
JS 中还可以通过函数创建出一个独立的作用域,其中函数可以嵌套,所以作用域也可以嵌套

作用域链

由于作用域是相对于变量而言的,而如果存在多级作用域,这个变量又来自于哪里?这个问题就需要好好地探究一下了,我们把这个变量的查找过程称之为变量的作用域链

简单来说,作用域链可以用以下几句话来概括:(或者说:确定一个变量来自于哪个作用域)

查看当前作用域,如果当前作用域声明了这个变量,就确定结果

查找当前作用域的上级作用域,也就是当前函数的上级函数,看看上级函数中有没有声明

再查找上级函数的上级函数,直到全局作用域为止
如果全局作用域中也没有,我们就认为这个变量未声明(xxx is not defined)

举例 1:

var name=” 张三 ”;
function f1(){
var name=”abc”;
console.log(name);
}
f1();
举例 2:
var name=” 张三 ”;
function f1(){
console.log(name);
var name=”abc”;
}
f1();
举例 3:
var name=” 张三 ”;
function f1(){
console.log(name);
var name=”abc”;
}
f1();
举例 4:
var name=” 张三 ”;
function f1(){
return function(){
console.log(name);
}
var name=”abc”;
}
var fn=f1();
fn();
举例 5:
var name=” 张三 ”;
function f1(){
return {
say:function(){
console.log(name);
var name=”abc”;
}
}
}
var fn=f1();
闭包的问题
function fn(){
var a=5;
return function(){
a++;
console.log(a);
}
}
var f1=fn();
f1();
f1();
f1();
闭包问题的产生原因
函数执行完毕后,作用域中保留了最新的 a 变量的值
闭包的应用场景

模块化
防止变量被破坏

es6 内容

1、解构赋值
2、函数 rest 参数

3、箭头函数
箭头函数和普通函数有哪些不同?(4 点)

4、对象的 Object.assign
5、promise
6、generator
7、async
8、class
9、module

原型

原型很多人开发用不到?

很多人都用 es6/7/ 8 开发,确实用的比较少
如果你用 es5 之前的版本开发代码(IE8、IE7。。。),可能天天都要写原型
理解了原型,才是理解了 JS 面向对象的核心,没有理解原型,你就没有理解面向对象的核心

ES6
node.js
vue
React
Angular
微信

正文完
 0