补充一些前端面试题

javascript有哪些库

指路=>js中的库

uniapp和vue有什么区别

什么是uniapp

uni-app(uni,读you ni,是统一的意思)是一个使用Vue.js开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序、快应用等多个平台。

vue和uniapp的区别

1、uniapp开发可以编译到(头条,支付宝,微信,QQ,百度)小程序,安卓版,ios版,h5版。通过打包实现一套代码多端运行;

2、vue是一个单页面应用,在app上面会卡死

3、vue是一个框架,开发的时候可以借助ui组件库进行开发

4、uniapp的开发主要依靠uniapp自己封装的组件,一可以借助外部的ui组件库

5、uniapp自带路由和请求方式

6、uni-app还有自动的框架预载,加载页面的速度更快。

7、里面的标签也发生了变化,

div 改成 view

span、font 改成 text

a 改成 navigator

img 改成 image

input 还在,但type属性改成了confirmtype

form、button、checkbox、radio、label、textarea、canvas、video

这些还在。

select 改成 picker

iframe 改成 web-view

ul、li没有了,都用view替代

null和undefined的区别

区别:

深层定义

  • null 指空对象,但它是被定义过的

  • undefined 指声明未赋值的对象或者是不存在的对象属性值

典型用法

null表示"没有对象",即该处不应该有值。典型用法是:

(1) 作为函数的参数,表示该函数的参数不是对象。

(2) 作为对象原型链的终点。

undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:

(1)变量被声明了,但没有赋值时,就等于undefined。

(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。

(3)对象没有赋值的属性,该属性的值为undefined。

(4)函数没有返回值时,默认返回undefined。

常见的状态码

成功类(请求已经被成功处理了)

200 请求已成功,返回想要的东西。出现此状态码是表示正常状态。(所有人都喜欢的)

201 请求成功,服务器正在创建请求的资源

202 服务器收到请求了,但是未处理

203 服务器成功处理,但是返回的信息是另一个来源

204 服务器成功处理,但是没有返回内容

205 服务器成功处理,但是没有返回内容

206 成功处理了部分get请求

重定向类(要完成请求,需要进一步操作)

300 针对请求,服务器可执行多种操作

301 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置

302 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求

304 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容

305 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理

请求错误(请求可能出错,导致服务器处理不了)

400 语义错误,请求无法被服务器理解。或者请求参数有误

401 请求需要请求者验证

403 服务器拒绝该请求

404 找不到请求网页

405 请求的方法是服务器中禁用的

406 请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体

408 请求超时

410 被请求的资源在服务器上已经不再可用,而且没有任何已知的转发地址

413 服务器拒绝处理当前请求,因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围

服务器错误

500 服务器代码报错

501 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码

502 服务器作为网关或代理,从上游服务器收到无效响应

503 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态

504 服务器作为网关或代理,但是没有及时从上游服务器收到请求

505 服务器不支持请求中所用的 HTTP 协议版本

var、let、const的区别

var的缺陷,先来看看使用var定义变量会有哪些问题:

1.var不是块级作用域,下面的代码循环已经结束了,却还可以访问到变量test,可能会引起bug

 for(var i=0;i<10;i++){
        var test = i;
    }

    console.log(test);//9
    console.log(i)//10 用来记数的变量也可以访问, 无意中就污染了全局变量

2.var定义的变量,有变量提升,变量提升,会对程序的维护带来困扰。

 if(true){
        console.log('执行了');
    }else{
        console.log('没执行');
        var j = 2;
    }

    console.log(j);   //输出undefined 定义变量j的代码虽然没有执行,但是却依然不会报错 

3.var定义的变量,不会为异步任务单独绑定变量,下面这段代码,本意是让它每隔一段时间输出

for (var i = 0; i < 3; i++) {
      setTimeout(function () {
        console.log(i)
      }, 1000);
 }

4.var定义的变量,可以重复定义,这样就显得非常的随意松散

 var a =1;
    var a =2;

    console.log(a);//输出后面定义的2

二、let和const就是ES6针对以上问题提出的解决方案,let和var的区别具体如下:

1.let声明的变量是块级作用域的,这个特性解决了原来使用var容易污染全局变量的弊端。

    for(let i=0;i<10;i++){
        let test = i;
    }

    console.log(i);//Uncaught ReferenceError: i is not defined
    console.log(test)//Uncaught ReferenceError: test is not defined

2.let声明的变量不存在变量提升,从let的块级作用域开始,到初始化位置,称作“暂存死区”,对于变量的暂存死区中使用变量会报Reference错误。这个特性就使得我们先定义变量再使用的变量,避免了var变量提升带来的难以查找的bug,也增强了代码的可读性。

 //使用var
    console.log(i); // 输出undefined
    var i = 2;

    //使用let
    console.log(j);
    let j =10; //Uncaught ReferenceError: Cannot access 'j' before initialization

3 var可以重复定义变量,而let不可以,使得定义变量不再像var那么随意

4 var定义的全局变量属于顶层对象,而let、const声明的全局变量不属于顶层对象的属性,这也很容易理解, 因为let的设计初衷就是块级作用域变量,不污染全局变量,显得自由灵活安全。以浏览器为例:

var a = 0;
console.log(window.a) // 0
let b = 1;
console.log(window.b) // undefined

三、以上let具有的特性,const都有,const和let的区别如下:

1.const在声明常量的时候, 一定要初始化一个值:

2.const定义的常量值不允许修改

四、总结

1.let和const声明的变量时块级作用域,避免了无意中全局变量污染,更加的灵活安全。另一个好处就是在循环语句中,let关键字为每次循环绑定单独绑定一个变量。

2.let和const没有变量提升,提高了代码的可维护性。

3.let和const不可以重复定义变量,修复var可以重复定义变量,使得变量的定义不再随意任性。

4.let和const定义的变量不属于顶层对象。目的也是为了让变量定义更加自由灵活安全。

5.const声明一个常量的时候,一定要赋值。

6.const声明的常量并非真正意义上的常量,只保证变量名指向的地址不变,并不保证该地址的数据不变。

for in 和for of的区别

  1. for in 和 for of 都可以循环数组,for in 输出的是数组的index下标,而for of 输出的是数组的每一项的值。

const arr = [1,2,3,4]
 
// for ... in
for (const key in arr){
    console.log(key) // 输出 0,1,2,3
    }
 
// for ... of
for (const key of arr){
    console.log(key) // 输出 1,2,3,4
    }

循环对象:

  1. for in 可以遍历对象,for of 不能遍历对象,只能遍历带有iterator接口的,例如Set,Map,String,Array

总结:for in适合遍历对象,for of适合遍历数组。for in遍历的是数组的索引,对象的属性,以及原型链上的属性。

原型与原型链的理解

原型:每个函数都有prototype属性,该属性指向原型对象。

使用原型对象的好处是所有对象实例共享它所包含的属性和方法。

原型链:访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会沿着它的_proto_ 属性所指向的那个对象(父对象)里找,直到为null为止,这样一层一层的就构成了原型链。

主要解决了继承的问题。

原型和原型对象

在JS中,我们所说的原型通常是针对于函数而言的,当然构造函数也是一个函数。

我们都知道函数也是一个对象,是对象那么它就有属性,在JS中,我们所创建的每一个函数自带一个属性prototype,我们就把prototype称为原型,有些小伙伴也把它称之为“显示原型”,反正就一个意思。

这个prototype它指向了一个对象,你可以把prototype想象成一个指针,或者更简单的理解为prototype的属性值(键值对)。prototype指向的这个对象我们就称之为原型对象,通常大家就直接将prototype理解为原型对象。

为了让大家更好理解,我们可以在浏览器控制台简单查看一下函数的prototype,如下图:

上图中我们声明了一个Person函数,既然函数是对象,那么我们就可以使用“.”来查看它的属性,可以看到有一个prototype属性,这个是每一个函数都有的。

总结

其实原型或者原型对象没有那么复杂,总结下来就下面几点:

每个函数都有prototype属性,被称作原型。

prototype原型指向一个对象,故也称作原型对象。

prototype和__ptoto__

很多小伙伴把prototype和__proto__混为一潭,其实这是两个维度的东西。prototype的维度是函数,而__proto__的维度是对象。__proto__是每个对象都有的属性,我们通常把它称为"隐式原型",把prototype称为"显式原型"。

有些小伙伴可能有疑惑,函数也是一个对象,那它是不是也有__proto__属性呢?答案是肯定的,我们可以通过浏览器控制台验证一下。

我们可以看到函数有prototype和__proto__两个属性,而对象只有__proto__属性。接下来我们再来看看__proto__属性有什么呢?

在浏览器控制台进行测试:

上图中我们发现了一个新的属性:[[Prototype]]。很多小伙伴会误认为这个就是我们所说的显式原型prototype,其实不是的,官方对于这个属性其实有解释,我们这里通俗的给大家解释一下:

[[prototype]]其实就是隐式原型__proto__,因为各大浏览器厂家不同,所以取了别名罢了,大家只需记住这个和__proto__一样即可。

上段代码中我们定义了一个空对象,它有一个隐式原型[[prototype]],隐式原型的constructor指向了构造函数Object。

总结

__proto__和prototype不太一样,一个是对象拥有的隐式原型,一个是函数拥有的显式原型,这里我们简单总结一下__proto__:

通常被称作隐式原型,每个对象都拥有该属性。

[[prototype]]其实就是__proto__。

原型链

<script>
  function Person(name) {
  }
  // 在函数的原型上添加变量和方法
  Person.prototype.name = "小猪课堂";
  Person.prototype.say = function () {
    console.log("你好小猪课堂");
  }


  let obj = new Person();
  console.log(obj.name); // 小猪课堂
  obj.say(); // 你好小猪课堂
</script>

我们声明了一个构造函数Person,其实就是一个函数。我们知道函数的prototype是一个对象,我们就可以往这个对象上添加东西,所以我们就直接往函数的原型上添加了变量和方法。

接着我们使用new关键词创建一个Person构造函数的实例对象,分别打印name和调用say方法,大家会发现输出结果其实都是Person原型上的东西。

我们会发现obj对象上面其实并没有name属性和say方法,但是在它的隐式原型[[prototype]]上有name和say,而且我们会发现obj的[[prototype]]中的constructor指向的式它的构造函数Person。

所以我们大胆的做一个猜想:obj的隐式原型__proto__是否和构造函数Person的显式原型prototype相等呢?我们用代码证实一下:

console.log(obj.__proto__ === Person.prototype) // true

<script>
  function Person(name) {
    this.name = name;
  }
  // 在函数的原型上添加变量和方法
  Person.prototype.name = "小猪课堂";
  Person.prototype.say = function () {
    console.log("你好小猪课堂");
  }


  let obj = new Person("张三");
  console.log(obj.name); // 张三
  obj.say(); // 你好小猪课堂


  console.log(obj)
</script>

上段代码中我们obj上面有自己的name属性了,这个时候输出的就是obj自带的name属性。到这里我们又可以做一个大胆的猜想:obj对象想要获取name或者say,首先判断自己的属性当中有没有,如果没有找到,那么就在__proto__属性中去找,而这个时候__proto__与Person的prototype是相等的,也就是__proto__指向Person,那么便可以找到name和say。

上面的猜想非常的正确!我们还可以在上面的猜想上扩展一下,既然函数的prototype是一个对象,那么它必然有__proto__,当我们在函数的原型上没有找到的时候,我们又继续查找prototype的__proto__,以此下去,直到找到或者__proto__没有指向某个构造函数为止。

上面的查找过程是不是很像链式查找啊!而这就是我们所说的原型链,而且我们发现查找的过程主要是通过__proto__原型来进行的,所以__proto__就是我们原型链中的连接点。

总结:

上面的查找的过程形成的一条线索就叫做原型链,大家可以把原型链拆开来理解:原型和链。

原型就是我们的prototype

链就是__proto__,它让整个链路连接起来。

想要理解原型链,我们还得理解__proto__指向哪儿,也就是说它指向那个构造函数,比如上面的obj对象的__proto__指向的就是Person构造函数,所以我们继续往Person上查找。

prototype、__proto__、 constructor三者之间的关系

prototype :原型(原型对象)指向的都是原型

__proto__:指向的都是原型

constructor:原型上的属性:指向的是构造函数

①每个对象都有一个隐式的属性(__proto__),属性值本质上就是一个普通的对象

②每个函数对象都有一个原型属性(prototype),属性值本质上就是一个普通的对象

③每个对象的__proto__指向构造函数的原型对象(prototype)

④原型对象上有constrctor属性,指向构造函数

URL从输入到页面渲染的过程

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值