阿八博客
  • 100000+

    文章

  • 23

    评论

  • 20

    友链

  • 最近新加了很多技术文章,大家多来逛逛吧~~~~
  • 喜欢这个网站的朋友可以加一下QQ群,我们一起交流技术。

前端Js笔试题面试题

欢迎来到阿八个人博客网站。本 阿八个人博客 网站提供最新的站长新闻,各种互联网资讯。 喜欢本站的朋友可以收藏本站,或者加QQ:我们大家一起来交流技术! URL链接:https://www.abboke.com/jsh/2019/1010/116950.html

前言

为了方便现在和以后前端学习和面试,在此收集和整理了Js相关的笔试面试题,供自己查阅的同时,希望也会对大家有所帮助

数据类型

JS的基本数据类型

Undefined、Null、Boolean、Number、String、新增:Symbol

JS有哪些内置对象?

Object 是 JavaScript 中所有对象的父对象

数据封装类对象:Object、Array、Boolean、Number 和 String

其他对象:Function、Arguments、Math、Date、RegExp、Error

JS中使用typeof能得到的哪些类型?(考点:JS变量类型)

typeof undefinded //undefinedtypeof null // objecttypeof'abc' // stringtypeof 123 // numbertypeof [] // objecttypeof {} // objecttypeof true //booleantypeof b // b 没有声明,但是还会显示 undefined

何时使用===何时使用==?(考点:强制类型转换)

== 比较两个值相等返回ture

=== 比较两者的值和类型都相等才返回true 严格相等

0,NAN,null,undefinded,'',false 在if语句中会强制转化为 false

if (obj.a == null) {    // 这里相当于 obj.a === null || obj.a ===undefinded, 简写形式    // 这里jquery 源码中推荐的写法}

null,undefined 的区别?

1、null: Null类型,代表“空值”,代表一个空对象指针,使用typeof运算得到 “object”,所以你可以认为它是一个特殊的对象值


2、undefined: Undefined类型,当一个声明了一个变量未初始化时,得到的就是undefined

<font color='red'>ps:一句话简单来说null和undefine值比较是相等,但类型不同
</font>

javascript创建对象的几种方式?

1、对象字面量的方式

var = {}

2、通过构造函数方式创建

var obj = new Object(); 

3、通过Object.create()方式创建

var obj = Object.create(Object.prototype);

翻转一个字符串

可以先将字符串转成一个数组,然后用数组的reverse()+join()方法

let str="hello word";let b=[...str].reverse().join("");//drow olleh

描述new一个对象的过程

1、创建一个新对象

2、this指向这个对象

3、执行代码,即对this赋值

4、隐式返回this

JS按存储方式区分变量类型

// 值类型var a = 10var b = aa = 11console.log(b) // 10// 引用类型var obj1 = {x : 100}var obj2 = obj1obj1.x = 200console.log(obj2) // 200

如何判断一个变量是对象还是数组?

1、instanceof方法
instanceof 运算符是用来测试一个对象是否在其原型链原型构造函数的属性

var arr = []; arr instanceof Array; // true

2、constructor方法
constructor属性返回对创建此对象的数组函数的引用,就是返回对象相对应的构造函数

var arr = []; arr.constructor == Array; //true

3、最简单的方法,这种写法兼容性最好使用Object.prototype.toString.call()

function isObjArr(value){     if (Object.prototype.toString.call(value) === "[object Array]") {            console.log('value是数组');       }else if(Object.prototype.toString.call(value)==='[object Object]'){//这个方法兼容性好一点            console.log('value是对象');      }else{          console.log('value不是数组也不是对象')      }}

4、ES5新增方法isArray()

var a = new Array(123);var b = new Date();console.log(Array.isArray(a)); //trueconsole.log(Array.isArray(b)); //false

<font color='red'>ps:千万不能使用typeof来判断对象和数组,因为这两种类型都会返回"object"

</font>

如何对一个数组去重?

1、Set结构去重(ES6用法)


ES6提供了新的数据结构Set
它类似于数组,但是成员的值都是唯一的,没有重复的值

[...new Set(array)];

2、遍历,将值添加到新数组,用indexOf()判断值是否存在,已存在就不添加,达到去重效果

  let a = ['1','2','3',1,NaN,NaN,undefined,undefined,null,null, 'a','b','b'];    let unique= arr =>{         let newA=[];        arr.forEach(key => {           if( newA.indexOf(key)<0 ){ //遍历newA是否存在key,如果存在key会大于0就跳过push的那一步             newA.push(key);           }        });        return newA;    }    console.log(unique(a)) ;//["1", "2", "3", 1, NaN, NaN, undefined, null, "a", "b"]// 这个方法不能分辨NaN,会出现两个NaN
是有问题的,下面那个方法好一点

3、利用for嵌套for,然后splice去重(ES5中最常用)

function unique(arr){                    for(var i=0; i<arr.length; i++){            for(var j=i+1; j<arr.length; j++){                if(arr[i]==arr[j]){         //第一个等同于第二个,splice方法删除第二个                    arr.splice(j,1);                    j--;                }            }        }return arr;}var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];    console.log(unique(arr))    //[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}]     //NaN和{}没有去重,两个null直接消失了

4、forEach遍历,然后利用Object.keys(对象)返回这个对象可枚举属性组成的数组,这个数组就是去重后的数组

    let a = ['1', '2', '3', 1,NaN,NaN,undefined,undefined,null,null, 'a', 'b', 'b'];    const unique = arr => {        var obj = {}        arr.forEach(value => {            obj[value] = 0;//这步新添加一个属性,并赋值,如果不赋值的话,属性会添加不上去        })        return Object.keys(obj);//`Object.keys(对象)`返回这个对象可枚举属性组成的数组,这个数组就是去重后的数组    }    console.log(unique(a));//["1", "2", "3", "NaN", "undefined", "null", "a", "b"]    

作用域和闭包

var、let、const之间的区别

var声明变量可以重复声明,而let不可以重复声明

var是不受限于块级的,而let是受限于块级

var会与window相映射(会挂一个属性),而let不与window相映射

var可以在声明的上面访问变量,而let有暂存死区,在声明的上面访问变量会报错

const声明之后必须赋值,否则会报错

const定义不可变的量,改变了就会报错

const和let一样不会与window相映射、支持块级作用域、在声明的上面访问变量会报错

说明this几种不同的使用场景

1、作为构造函数执行

2、作为对象属性执行

3、作为普通函数执行

4、call apply bind

谈谈This对象的理解

1、this总是指向函数的直接调用者(而非间接调用者)

2、如果有new关键字,this指向new出来的那个对象

3、在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window

作用域

ES5作用域分为 全局作用域 和 函数作用域


ES6新增块级作用域,块作用域由 { } 包括,if语句和 for语句里面的{ }也属于块作用域

// 块级作用域if (true) {    var name = 'zhangsan'}console.log(name)// 函数和全局作用域var a = 100function fn () {    var a = 200    console.log('fn', a)}

用JS创建10个<a>标签,点击的时候弹出来对应的序号?(考点:作用域)

var i for (i = 0; i < 10; i++) {    (function (i) {        var a = document.createElement('a')        a.innerHTML = i + '<br>'        a.addEventListener('click', function (e) {            e.preventDefault()            alert(i)        })        document.body.appendChild(a)    })(i)}

说说你对作用域链的理解

1、作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的

2、简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期

3、通俗来说,一般情况下,变量取值到 创建 这个变量 的函数的作用域中取值

但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链

var a = 100function fn () {    var b = 200    // 当前作用域没有定于的变量,即‘自由变量’    console.log(a)    console.log(b)}fn()console.log(a) 去父级作用域找a自由变量 作用域链

闭包

闭包就是能够读取其他函数内部变量的函数

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域

function F1 () {    var a = 100    // 返回一个函数,函数作为返回值    return function () {        console.log(a)    }}// f1 得到一个函数var f1 = F1()var a = 200f1()  // 100 定义的时候父级作用域

闭包的特性

函数内再嵌套函数

内部函数可以引用外层的参数和变量

参数和变量不会被垃圾回收机制回收

说说你对闭包的理解

使用闭包主要是为了设计私有的方法和变量
闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露
在js中,函数即闭包,只有函数才会产生作用域的概念

闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中

闭包的另一个用处,是封装对象的私有属性和私有方法

好处:能够实现封装和缓存等;

坏处:就是消耗内存、不正当使用会造成内存溢出的问题

使用闭包的注意点

由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露
解决方法是,在退出函数之前,将不使用的局部变量全部删除

闭包的使用场景

闭包的两个场景:函数作为返回值 和 函数作为参数传递

function F1 () {    var a = 100    // 返回一个函数,函数作为返回值    return function () {        console.log(a)    }}// f1 得到一个函数var f1 = F1()var a = 200f1()  // 100 定义的时候父级作用域function F2 (fn) {    var a = 200    fn()}F2(f1)

实际开发中闭包的应用

// 闭包实际应用中主要用于封装变量 收敛权限function isFirstLoad() {    var _list = []    return function (id) {        if (_list.indexOf(id) >= 0) {            return false        } else {            _list.push(id)            return true        }    }}// 使用var firstLoad = new isFirstLoad()firstLoad(10) //truefirstLoad(10) //falsefirstLoad(30) //true

原型和原型链

JavaScript原型,原型链 ? 有什么特点?

每个对象都会在其内部初始化一个属性,就是prototype(原型),
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念

<font color='red'>原型和原型链关系</font>

关系:instance.constructor.prototype = instance.__proto__

<font color='red'>原型和原型链特点</font>

JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本
当我们修改原型时,与之相关的对象也会继承这一改变
当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的
就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象

<font color='red'>PS:</font>
1.所有的引用类型(数组,对象,函数)都具有对象的特性,即可自由扩展属性(除了‘null’)除外

2.所有的引用类型(数组,对象,函数)都有一个_proto_(隐式原型)属性,属性值是一个普通对象

3.所有的函数,都有一个prototype(显示原型)的属性,也是一个普通对象

4.所有的引用类型(数组,对象,函数)_proto_属性值指向他的构造的‘prototype’ 属性值

当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的_proto_(即它的构造函数的prototype) 中寻找

// 构造函数function Foo(name, age){    this.name = name }Foo.prototype.alertName = function () {    alert(this.name)}//创建实例var f = new Foo('zhangsan')f.printName = function () {    console.log(this.name)}//测试f.printName()f.alertName()

循环对象自身的属性

var itemfor (item in f) {    // 高级浏览器已经在 for in 中屏蔽了来自原型的属性    // 但是这里建议大家还是加上这个判断,保证程序的健壮性    if (f.hasOwnProperty(item)) {        console.log(item)    }}

原型链

f.toString() //到f._proto_._proto_ 中去找

异步和单线程

同步和异步的区别是什么?分别举一个同步和异步的例子

<font color='red'>同步交互:</font>指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程;
 <font color='red'>异步交互:</font>指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待


相同的地方:都属于交互方式,都是发送请求


不同的地方:一个需要等待,一个不需要等待


简单而言,同步就是必须一件一件的做事,等前一件事做完后才能做下一件事
而异步这是把事情指派给别人后,接着继续做下一件事,不必等别人返回的结果


举例:

1、广播,就是一个异步例子
发起者不关心接收者的状态
不需要等待接收者的返回信息;
在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式


2、电话,就是一个同步例子
发起者需要等待接收者,接通电话后,通信才开始
需要等待接收者的返回信息
比如银行的转账系统,对数据库的保存操作等等,都会使用同步交互操作


<font color='red'>ps: </font>alert是同步,setTimeout和setInterval是异步,同步会阻塞代码执行,而异步不会

异步编程的实现方式?

1、<font color='red'>回调函数</font>

优点:简单、容易理解

缺点:不利于维护,代码耦合高

2、<font color='red'>事件监听(采用时间驱动模式,取决于某个事件是否发生):</font>

优点:容易理解,可以绑定多个事件,每个事件可以指定多个回调函数

缺点:事件驱动型,流程不够清晰

3、<font color='red'>发布/订阅(观察者模式)</font>

类似于事件监听,但是可以通过‘消息中心’,了解现在有多少发布者,多少订阅者

4、<font color='red'>Promise对象</font>

优点:可以利用then方法,进行链式写法;可以书写错误时的回调函数;

缺点:编写和理解,相对比较难

5、<font color='red'>Generator函数</font>

优点:函数体内外的数据交换、错误处理机制

缺点:流程管理不方便

6、<font color='red'>async函数</font>

优点:内置执行器、更好的语义、更广的适用性、返回的是Promise、结构清晰


缺点:错误处理机制

定时器的执行顺序或机制

简单来说:因为js是单线程的,浏览器遇到setTimeout或者setInterval会先执行完当前的代码块,在此之前会把定时器推入浏览器的待执行事件队列里面,等到浏览器执行完当前代码之后会看一下事件队列里面有没有任务,有的话才执行定时器的代码
所以即使把定时器的时间设置为0还是会先执行当前的一些代码

一个关于setTimeout的笔试题

console.log(1)setTimeout(function () {    console.log(2)},0)console.log(3)setTimeout(function () {console.log(4)},1000)console.log(5)//结果为 1 3 5 2 4

前段使用异步的场景

1、定时任务:setTimeout,setInverval

2、网络请求:ajax请求,动态<img>加载

3、事件绑定

数组和对象API

map与forEach的区别?

1、forEach方法,是最基本的方法,就是遍历与循环,默认有3个传参:分别是遍历的数组内容item、数组索引index、和当前遍历数组Array

2、map方法,基本用法与forEach一致,但是不同的,它会返回一个新的数组,所以在callback需要有return值,如果没有,会返回undefined

JS 数组和对象的遍历方式,以及几种方式的比较

通常我们会用循环的方式来遍历数组
但是循环是 导致js 性能问题的原因之一
一般我们会采用下几种方式来进行数组的遍历

<font color='red'>for in循环</font>

<font color='red'>for循环</font>

<font color='red'>forEach</font>

1、这里的 forEach回调中两个参数分别为 value,index

2、forEach 无法遍历对象

3、IE不支持该方法;Firefox 和 chrome 支持

4、forEach 无法使用 break,continue 跳出循环,且使用 return 是跳过本次循环

5、可以添加第二个参数,为一个数组,回调中的this会指向这个数组,若没有添加,则是指向 window;

<font color='red'>在方式一中</font>,for-in需要分析出array的每个属性,这个操作性能开销很大
用在 key 已知的数组上是非常不划算的
所以尽量不要用for-in,除非你不清楚要处理哪些属性,例如 JSON对象这样的情况

<font color='red'>在方式2中</font>,循环每进行一次,就要检查一下数组长度
读取属性(数组长度)要比读局部变量慢,尤其是当 array 里存放的都是 DOM 元素,因为每次读取都会扫描一遍页面上的选择器相关元素,速度会大大降低

写一个能遍历对象和数组的通用forEach函数

function forEach(obj, fn) {    var key    // 判断类型    if (obj instanceof Array) {        obj.forEach(function (item, index) {            fn(index, item)        })    } else {        for (key in obj) {            fn ( key, obj[key])        }    }}

数组API

map: 遍历数组,返回回调返回值组成的新数组forEach: 无法break,可以用try/catch中throw new Error来停止filter: 过滤some: 有一项返回true,则整体为trueevery: 有一项返回false,则整体为falsejoin: 通过指定连接符生成字符串push / pop: 末尾推入和弹出,改变原数组, 返回推入/弹出项【有误】unshift / shift: 头部推入和弹出,改变原数组,返回操作项【有误】sort(fn) / reverse: 排序与反转,改变原数组concat: 连接数组,不影响原数组, 浅拷贝slice(start, end): 返回截断后的新数组,不改变原数组splice(start, number, value...): 返回删除元素组成的数组,value 为插入项,改变原数组indexOf / lastIndexOf(value, fromIndex): 查找数组项,返回对应的下标reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur 为当前值(从第二项开始)

对象API

var obj = {    x: 100,    y: 200,    z: 300} var keyfor (key in obj) {    // 注意这里的 hasOwnProperty,再讲原型链的时候讲过    if (obj.hasOwnProperty(key)) {        console.log(key, obj[key])    }}

日期和随机数

获取2020-06-10格式的日期

Date.now() // 获取当前时间毫秒数var dt = new Date()dt.getTime() //获取毫秒数dt.getFullYear() // 年dt.getMonth() // 月 (0-11)dt.getDate() // 日 (0-31)dt.getHours() // 小时 (0-23)dt.getMinutes() //分钟 (0-59)dt.getSeconds() //秒 (0-59)

<font color='red'>ps: ES6 新增padStart(),padEnd()方法可用来返回06格式日期</font>

获取随机数,要求是长度一致的字符串格式

var random = Math.random()var random = random + '0000000000'console.log(random)var random = random.slice(0, 10)console.log(random)

DOM和BOM操作

DOM是哪种基本的数据结构

DOM是一种树形结构的数据结构

DOM操作的常用API有哪些

1、获取DOM节点,以及节点的property和Attribute

2、获取父节点,获取子节点

3、新增节点,删除节点

DOM节点的Attribute和property有何区别

property只是一个JS对象的属性修改和获取

Attribute是对html标签属性的修改和获取

DOM的节点操作

创建新节点

createDocumentFragment()    //创建一个DOM片段createElement()   //创建一个具体的元素createTextNode()   //创建一个文本节点

添加、移除、替换、插入

appendChild()      //添加removeChild()      //移除replaceChild()      //替换insertBefore()      //插入

查找

getElementsByTagName()    //通过标签名称getElementsByName()     //通过元素的Name属性的值getElementById()        //通过元素Id,唯一性

如何检测浏览器的类型

可以通过检测navigator.userAgent 在通过不通浏览器的不通来检测

var ua = navigator.userAgentvar isChrome = ua.indexOf('Chrome')console.log(isChrome)

拆解url的各部分

使用location 里面的location.href location.protocol location.pathname location.search location.hash来获取各种参数

console.log(location.href)console.log(location.host) //域名console.log(location.protocol)console.log(location.pathname) //路径console.log(location.search) // 参数console.log(location.hash) // historyhistory.back()history.forward()

事件机制

请解释什么是事件代理

事件代理(Event Delegation),又称之为事件委托
是 JavaScript 中常用绑定事件的常用技巧
顾名思义,“事件代理”即是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务
事件代理的原理是DOM元素的事件冒泡

使用事件代理的好处是:

1、可以提高性能

2、可以大量节省内存占用,减少事件注册,比如在table上代理所有td的click事件就非常棒

3、可以实现当新增子对象时无需再次对其绑定

事件模型

W3C中定义事件的发生经历三个阶段:捕获阶段(capturing)、目标阶段(targetin)、冒泡阶段(bubbling)

冒泡型事件:当你使用事件冒泡时,子级元素先触发,父级元素后触发

捕获型事件:当你使用事件捕获时,父级元素先触发,子级元素后触发

DOM事件流:同时支持两种事件模型:捕获型事件和冒泡型事件

阻止冒泡:在W3c中,使用stopPropagation()方法;在IE下设置cancelBubble = true

阻止捕获:阻止事件的默认行为,例如click - <a>后的跳转
在W3c中,使用preventDefault()方法,在IE下设置window.event.returnValue = false

编写一个通用的事件监听函数

function bindEvent(elem,type,selector,fn){    if(fn==null){        fn = selector;        selector = null    }    elem.addEventListener(type,function(e){        var target;        if(selector){            target = e.target;            if(target.matches(selector)){                fn.call(target,e)            }        }else{            fn(e)        }    })}

描述事件冒泡流程

当给某元素绑定一个事件的时候,首先会触发自己绑定的,然后会逐层向上级查找事件,这就是事件冒泡

var p1 = document.getElementById('p1')        var body = document.body        function bindEvent(elem, type, fn) {            elem.addEventListener(type, fn)        }         bindEvent(p1, 'click', function (e) {                e.stopPropagation()                var target = e.target                alert("激活")            })            bindEvent(body, 'click', function (e) {                var target = e.target                alert("取消")            })

对于一个无限下拉加载图片的页面,如何给每个图片绑定事件

可以使用代理,通过对父级元素绑定一个事件,通过判断事件的target属性来进行判断,添加行为

var div1 = document.getElementById('div1')        var div2 = document.getElementById('div2')        function bindEvent(elem, type, fn) {            elem.addEventListener(type, fn)        }         bindEvent(div1, 'click', function (e) {                var target = e.target                alert(target.innerHTML)            })        bindEvent(div2, 'click', function (e) {                var target = e.target                alert(target.innerHTML)        })

AJAX

Ajax原理

Ajax的原理简单来说是在用户和服务器之间加了—个中间层(AJAX引擎),通过<font color='red'>XmlHttpRequest</font>对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面
使用户操作与服务器响应异步化
这其中最关键的一步就是从服务器获得请求数据

Ajax的过程只涉及JavaScript、XMLHttpRequest和DOM
<font color='red'>XMLHttpRequest</font>是ajax的核心机制

手动编写一个ajax,不依赖第三方库

// 1. 创建连接    var xhr = null;    xhr = new XMLHttpRequest()    // 2. 连接服务器    xhr.open('get', url, true)    // 3. 发送请求    xhr.send(null);    // 4. 接受请求    xhr.onreadystatechange = function(){        if(xhr.readyState == 4){            if(xhr.status == 200){                success(xhr.responseText);            } else { // fail                fail && fail(xhr.status);            }        }    }

ajax的优点和缺点

<font color='red'>ajax的优点</font>

1、无刷新更新数据(在不刷新整个页面的情况下维持与服务器通信)

2、异步与服务器通信(使用异步的方式与服务器通信,不打断用户的操作)

3、前端和后端负载均衡(将一些后端的工作交给前端,减少服务器与宽度的负担)

4、界面和应用相分离(ajax将界面和应用分离也就是数据与呈现相分离)

<font color='red'>ajax的缺点</font>

1、ajax不支持浏览器back按钮

2、安全问题 Aajax暴露了与服务器交互的细节

3、对搜索引擎的支持比较弱

4、破坏了Back与History后退按钮的正常行为等浏览器机制

什么情况下会碰到跨域问题?有哪些解决方法?

跨域问题是这是浏览器为了安全实施的同源策略导致的,同源策略限制了来自不同源的<font color='red'>document、脚本</font>,同源的意思就是两个URL的域名、协议、端口要完全相同


script标签jsonp跨域、nginx反向代理、node.js中间件代理跨域、后端在头部信息设置安全域名、后端在服务器上设置cors


<font color='red'>ps:有三个标签允许跨域加载资源:
<img src=xxx> <link href = xxx> <script src=xxx>

三个标签场景:

<img> 用于打点统计,统计网站可能是其他域

<link> <script> 可以使用CDN,CDN的也是其他域

<script>可以用于JSONP</font>

⚠️跨域注意事项

所有的跨域请求都必须经过信息提供方允许

如果未经允许即可获取,那么浏览器同源策略出现漏洞

XML和JSON的区别?

数据体积方面

JSON相对于XML来讲,数据的体积小,传递的速度更快些

数据交互方面

JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互

数据描述方面

JSON对数据的描述性比XML较差

传输速度方面

JSON的速度要远远快于XML

get和post的区别

1、get和post在HTTP中都代表着请求数据,其中get请求相对来说更简单、快速,效率高些

2、get相对post安全性低

3、get有缓存,post没有

4、get体积小,post可以无限大

5、get的url参数可见,post不可见

6、get只接受ASCII字符的参数数据类型,post没有限制

7、get请求参数会保留历史记录,post中参数不会保留

8、get会被浏览器主动catch,post不会,需要手动设置

9、get在浏览器回退时无害,post会再次提交请求

<font color='red'>什么时候使用post?</font>

post一般用于修改服务器上的资源,对所发送的信息没有限制
比如

1、无法使用缓存文件(更新服务器上的文件或数据库)

2、向服务器发送大量数据(POST 没有数据量限制)

3、发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

ES6

ES5的继承和ES6的继承有什么区别?

ES5的继承时通过prototype或构造函数机制来实现
ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))

ES6的继承机制完全不同,实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this

具体的:ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承
子类必须在constructor方法中调用super方法,否则新建实例报错
因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工
如果不调用super方法,子类得不到this对象

ps:super关键字指代父类的实例,即父类的this对象
在子类构造函数中,调用super后,才可使用this关键字,否则报错

javascript如何实现继承?

1、构造继承

2、原型继承

3、实例继承

4、拷贝继承

<font color='red'>原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式</font>

function Parent(){        this.name = 'wang';    }    function Child(){        this.age = 28;    }    Child.prototype = new Parent();//继承了Parent,通过原型    var demo = new Child();    alert(demo.age);    alert(demo.name);//得到被继承的属性  }

谈谈你对ES6的理解

新增模板字符串(为JavaScript提供了简单的字符串插值功能)

箭头函数

for-of(用来遍历数据—例如数组中的值


arguments对象可被不定参数和默认参数完美代替


ES6将promise对象纳入规范,提供了原生的Promise对象


增加了let和const命令,用来声明变量


增加了块级作用域


let命令实际上就增加了块级作用域


还有就是引入module模块的概念

谈一谈箭头函数与普通函数的区别?

函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象

不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误

不可以使用arguments对象,该对象在函数体内不存在
如果要用,可以用Rest参数代替

不可以使用yield命令,因此箭头函数不能用作Generator函数

forEach、for in、for of三者区别

forEach更多的用来遍历数

for in 一般常用来遍历对象或json

for of数组对象都可以遍历,遍历对象需要通过和Object.keys()

for in循环出的是key,for of循环出的是value

Set、Map的区别

应用场景Set用于数据重组,Map用于数据储存

Set:

1,成员不能重复

2,只有键值没有键名,类似数组

3,可以遍历,方法有add, delete,has

Map:

1,本质上是健值对的集合,类似集合

2,可以遍历,可以跟各种数据格式转换

promise对象的用法,手写一个promise

promise是一个构造函数,下面是一个简单实例

var promise = new Promise((resolve,reject) => {    if (操作成功) {        resolve(value)    } else {        reject(error)    }})promise.then(function (value) {    // success},function (value) {    // failure})

请描述一下Promise的使用场景,'Promise'它所解决的问题以及现在对于异步操作的解决方案

Promise的使用场景:ajax请求,回调函数,复杂操作判断


Promise是ES6为了解决异步编程所诞生的


异步操作解决方案:Promise、Generator、定时器(不知道算不算)、还有ES7的async

ECMAScript6 怎么写class,为什么会出现class这种东西?

这个语法糖可以让有OOP基础的人更快上手js,至少是一个官方的实现了
但对熟悉js的人来说,这个东西没啥大影响;一个Object.creat()搞定继承,比class简洁清晰的多

算法和其他

冒泡排序

每次比较相邻的两个数,如果后一个比前一个小,换位置

var arr = [3, 1, 4, 6, 5, 7, 2];function bubbleSort(arr) {for (var i = 0; i < arr.length - 1; i++) {    for(var j = 0; j < arr.length - i - 1; j++) {        if(arr[j + 1] < arr[j]) {            var temp;            temp = arr[j];            arr[j] = arr[j + 1];            arr[j + 1] = temp;        }    }}return arr;}console.log(bubbleSort(arr));

快速排序

采用二分法,取出中间数,数组每次和中间数比较,小的放到左边,大的放到右边

var arr = [3, 1, 4, 6, 5, 7, 2];function quickSort(arr) {    if(arr.length == 0) {        return [];    // 返回空数组    }    var cIndex = Math.floor(arr.length / 2);    var c = arr.splice(cIndex, 1);    var l = [];    var r = [];    for (var i = 0; i < arr.length; i++) {        if(arr[i] < c) {            l.push(arr[i]);        } else {            r.push(arr[i]);        }    }    return quickSort(l).concat(c, quickSort(r));}console.log(quickSort(arr));

懒加载

<img id="img1" src="preview.png" data-realsrc = "abc.png"/><script type = "text/javascript">var img1 = document.getElementById("img1")img1.src = img1.getAttribute('data-realsrc')</script>

缓存DOM查询

// 未缓存 DOM查询var ifor (i = 0; i < document.getElementByTagName('p').length; i++) {    //todo}//缓存了DOM查询var pList = document.getElementByTagName('p')var i for (i= 0; i < pList.length; i++) {    // todo}

合并DOM插入

var listNode = document.getElementById('list')//要插入10个li标签var frag = document.createDocumentFragment();var x,lifor (x = 0; x < 10; x++) {    li = document.createElement('li')    li.innerHTML = "List item" + x    frag.appendChild(li)}listNode.appendChild(frag)

事件节流

var textarea = document.getElementById('text')var timeoutIdtextarea.addEventListener('keyup', function () {    if (timeoutId) {        clearTimeout(timeoutId)    }    timeoutId = setTimeout(function () {        //触发事件        },100)})

尽早操作

window.addEventListener('load', function () {    //页面的全部资源加载完才会去执行,包括图片,视频})document.addEventListener('DOMContentLoaded', function() {    //DOM 渲染完即可执行,此时图片,视频还可能没有加载完成})

浅拷贝

首先可以通过 Object.assign 来解决这个问题

let a = {    age: 1}let b = Object.assign({}, a)a.age = 2console.log(b.age) // 1

深拷贝

这个问题通常可以通过 JSON.parse(JSON.stringify(object)) 来解决

let a = {    age: 1,    jobs: {        first: 'FE'    }}let b = JSON.parse(JSON.stringify(a))a.jobs.first = 'native'console.log(b.jobs.first) // FE

数组降维

[1, [2], 3].flatMap(v => v)// -> [1, 2, 3]

如果想将一个多维数组彻底的降维,可以这样实现

const flattenDeep = (arr) => Array.isArray(arr)  ? arr.reduce( (a, b) => [...a, ...flattenDeep(b)] , [])  : [arr]flattenDeep([1, [[2], [3, [4]], 5]])

预加载

在开发中,可能会遇到这样的情况
有些资源不需要马上用到,但是希望尽早获取,这时候就可以使用预加载
预加载其实是声明式的 fetch ,强制浏览器请求资源,并且不会阻塞 onload 事件,可以使用以下代码开启预加载

<link rel="preload" href="http://example.com">

预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的文件延后加载,唯一缺点就是兼容性不好

预渲染

可以通过预渲染将下载的文件预先在后台渲染,可以使用以下代码开启预渲染

<link rel="prerender" href="http://poetries.com">

性能优化

JavaScript性能优化

1、尽可能把 <script> 标签放在 body 之后,避免 JS 的执行卡住 DOM 的渲染,最大程度保证页面尽快地展示出来2、尽可能合并 JS 代码:提取公共方法,进行面向对象设计等……3、CSS 能做的事情,尽量不用 JS 来做,毕竟 JS 的解析执行比较粗暴,而 CSS 效率更高
4、尽可能逐条操作 DOM,并预定好 CSs 样式,从而减少 reflow 或者 repaint 的次数
5、尽可能少地创建 DOM,而是在 HTML 和 CSS 中使用 display: none 来隐藏,按需显示
6、压缩文件大小,减少资源下载负担

JavaScript几条基本规范

1、不要在同一行声明多个变量2、请使用===/!==来比较true/false或者数值3、使用对象字面量替代new Array这种形式4、不要使用全局变量5、Switch语句必须带有default分支6、函数不应该有时候有返回值,有时候没有返回值7、For循环必须使用大括号8、IF语句必须使用大括号9、for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染

相关文章

暂住......别动,不想说点什么吗?
  • 全部评论(0
    还没有评论,快来抢沙发吧!