前端面试题个人总结( 一 )(持续更新)

498 阅读12分钟

xishi.jpeg

前言

本人三年前端小菜鸡,苦逼搬砖狗,这是一个用于记录面试多年遇到的面试题都是比较基础的问题,第一次写顺序比较混乱没什么章法,仅供参考、欢迎指正

1、闭包

密闭的容器,类型于set,map容器,存储数据的

形成的条件:

  1. 函数嵌套
  2. 内部函数引用外部函数的局部变量

闭包的优点:

延长外部函数的生命周期

闭包的缺点:

容易造成内存泄露

注意点:

要合理的使用,用完要及时清除

举个🌰

function fun(){
var i = 0;
    return fun2(){
    alert(++i);
    }
}
var a = fun();
a();  //1
a();  //2

vue和react的区别

相同点:

  1. 数据绑定:vue实现了数据的双向绑定,react数据流动是单向的
  2. 组件写法不一样,react是jsx,vue是webpack+vue-loader的单文件格式
  3. 在react中state对象是不可变,需要使用setState方法更新状态,而vue中state对象不是必须的,数据由data属性在vue对象中管理
  4. virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树,而对于react而言,每当应用的状态被改变时,全部的组件都会重新渲染
  5. react严格上只针对MVC的view层,vue则是MVVM模式

redux

redux是一个独立专门用于做状态管理的js库,它可以用在react、angular、vue等项目中,但基本与react配合使用,它的作用是集中式管理react应用中多个组件共享的状态和从后台获取的数据

image.png

image.png

vuex管理状态的机制

vuex是一个专门为vue开发的状态管理插件,用于集中式管理vue多个组件共享的状态和后台获取的数据

vuex属性:

  1. state: 存储组件需要的数据
  2. getters:处理store.js的事件方法
  3. mutations:组件处理store.js的事件方法
  4. actions:异步处理mutations里面的事件方法

image.png

vue-router

原理:更新视图但不重新请求页面

  1. hash:使用URL hash值作为路由,默认包含#,hash是URL中的锚点,代表网页中的一个位置,,单单改变#后面的部分,浏览器只会加载相应位置的内容,不会重新加载页面,通过锚点值改变,根据不同的值,渲染指定DOM位置不同的位置;随着 ajax 的流行,异步数据请求交互运行在不刷新浏览器的情况下进行。而异步交互体验的更高级版本就是 SPA —— 单页应用。单页应用不仅仅是在页面交互是无刷新的,连页面跳转都是无刷新的,为了实现单页应用,所以就有了前端路由。类似于服务端路由,前端路由实现起来其实也很简单,就是匹配不同的 url 路径,进行解析,然后动态的渲染出区域 html 内容。但是这样存在一个问题,就是 url 每次变化的时候,都会造成页面的刷新。那解决问题的思路便是在改变 url 的情况下,保证页面的不刷新。在 2014 年之前,大家是通过 hash 来实现路由,url hash 就是类似于:
http://www.xxx.com/#/login

这种 #。后面 hash 值的变化,并不会导致浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。另外每次 hash 值的变化,还会触发hashchange 这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听hashchange来实现更新页面部分内容的操作:

function matchAndUpdate () {
   // todo 匹配 hash 做 dom 更新操作
}

window.addEventListener('hashchange', matchAndUpdate)
  1. history:window对象,HTML5新增的API,history模式则会将URL修改的和正常请求后端的URL一样,如果后端没有配置对应的路由则会返回404错误,所以需要和后端配合在服务器端增加一个覆盖所有情况的候选资源,比如匹配不到返回同一个index.html页面; 14年后,因为HTML5标准发布。多了两个 API,pushState 和 replaceState,通过这两个 API 可以改变 url 地址且不会发送请求。同时还有popstate 事件。通过这些就能用另一种方式来实现前端路由了,但原理都是跟 hash 实现相同的。用了 HTML5 的实现,单页路由的 url 就不会多出一个#,变得更加美观。但因为没有 # 号,所以当用户刷新页面之类的操作时,浏览器还是会给服务器发送请求。为了避免出现这种情况,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面。
function matchAndUpdate () {
   // todo 匹配路径 做 dom 更新操作
}

window.addEventListener('popstate', matchAndUpdate)

什么是websocket

HTML5新增的协议,目的是在浏览器和服务器之间建立一个不受限的双向通信的通道,比如说,服务器可以在任意时刻发送消息给服务器,无需循环等待(长轮询),建立在TCP协议之上,服务器端的实现比较容易,websocket是一个典型的应用层协议; 与HTTP协议有着良好的兼容性,默认端口也是80和443,并且握手阶段采用HTTP协议,因此握手时不容易屏蔽,能通过各种HTTP代理服务器。

websocket优点

数据格式比较轻量,性能开销小,通信高效,可以发送文本,也可以发送二进制数据,没有同源限制客户端可以与任意服务器通信,协议标识符是ws(加密是wss)

继承

继承是面向对象中一个非常重要的特征,指的是子类继承父类的属性和方法

继承的好处:

  1. 子类拥有父类所有的属性和方法(代码复用)
  2. 子类可以扩展自己的属性和方法(更灵活)
  3. 子类可以重写父类的方法

继承的方式

原型链继承

拿父类实例来充当子类原型对象 缺点:

  • 无法继承构造函数中的属性
  • 创建子类实例时,无法向父类构造函数传参
  • 原型对象中存在多余的属性
借用构造函数

核心:借父类的构造函数来增强子类实例,相当于把父类的实例属性复制一份给子类实例\

  • call: 格式:父类构造函数.call(子类实例,参数1,参数2,参数3...)

  • apply: 格式:父类构造函数.apply(子类实例,[参数1,参数2,参数3...])

    call与apply的唯一区别:传参方式不同,call多个参数,apply只有两个参数,第二个参数为数组

var arr = [20,2,40,33,21,8,22,46,32]
    Math.max.apply(null,arr)
组合继承

由于以上继承方法的缺点,实际开发中不可能单纯的只使用一种继承方法,而是利用它们的优点,规避它们的缺点,所以就有了组合继承法

  • 继承属性:借用构造函数

    只在构造函数中定义属性

  • 继承方法:原型链继承

    把所有的方法写入原型对象

组合继承是最常用的继承模式。

  • 缺点(原型链继承法的缺点):

    • 在原型对象中生成多余的属性
    • 多次执行父类构造函数
原型式继承
  • 核心:先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时构造函数的一个新实例

    解决原型链继承法的缺点:生成多余的属性

    function object(o){
        function F(){}
        F.prototype = o;
        return new F();
    }
  • ES5版本的原型式继承:Object.create()
寄生组合继承法

完美的继承方法

  • 核心:

    • 继承属性:借用构造函数
    • 继承方法:原型式继承

ES6中的继承

### Class定义类[](https://vipkshttps0.wiz.cn/ks/note/view/f0ed86ae-ed03-448b-a406-2630767bb636/e654ce16-0d1d-4419-97be-2aa05b8d7bd7/#class "Permanent link")

ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类

//定义类
class Person {
    constructor(name,age) {
        this.name = name;
        this.age = age;
    }
    getInfo() {
         return `我叫${this.name},今年${this.age}岁`;;
    }
}
  • 写在类里面的方法实际是给Person.prototype添加方法
  • constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。如果没有constructor方法,则得使用默认的constractor方法

extends继承

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

class Man extends Person {
    constructor(name, age, gender) {
        //this.gender = gender; // 报错
        super(name, age);
        this.gender = gender; // 正确
    }
}            
  • 子类继承了父类,在子类构造函数中必须调用super方法。
  • 子类的constructor方法没有调用super之前,不能使用this关键字,否则报错,而放在super方法之后就是正确的。

跨域

什么是跨域

同源策略:

-是浏览器安全策略

-协议名、域名、端口号必须一致

Vue组件间的通信方式

1、通信种类

1、父组件向子组件通信

2、子组件向父组件通信

3、隔代组件间通信

4、兄弟组件间通信

2、实现通信的方式

1、props

2、Vue自定义事件

3、消息订阅与发布

4、vuex

5、slot

3、方式1:props

1、通过一般属性实现父子通信

2、通过函数属性实现子向父通信

3、缺点:隔代组件和兄弟组件间通信比较麻烦

4、方式2:vue自定义事件

1、vue内置实现,可以代替函数类型的props

a、绑定监听:<MyComp @eventName="callback"

b、触发(分发)事件:贴合$emit("evventName",data)

2、缺点:只适合于子向父通信

5、方式3:消息订阅与发布

1、需要引入消息订阅与发布的实现库,如:pubsub-js

a、订阅消息:PubSub.subscribe('msg', (msg,data){})

b、发布消息:PunSub.publish('msg',data)

2、优点:此方式可实现任意关系组件间通信

6、方式4:vuex

1、是什么:vuex是vue官方提供的集中式管理vue多组件共享状态数据的vue插件

2、优点:对组件间关系没有限制,且相比于pubsub库管理更集中,更方便

7、方式5:slot

1、是什么:专门用来实现父子通信传数据

2、注意:通信的标签模板是在父组件中解析好后再传递给子组件

ajax和axios的区别

ajax

是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

传统 ajax指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始js中,核心使用XMLHttpRequest对象,多个请求之间如果有先后关系的话,就会出现回调地狱。

JQuery ajax 是对原生XHR的封装,除此以外还增添了对JSONP的支持。经过多年的更新维护,真的已经是非常的方便了,优点无需多言;如果是硬要举出几个缺点,那可能只有:

1.本身是针对MVC的编程,不符合现在前端MVVM的浪潮

2.基于原生的XHR开发,XHR本身的架构不清晰。

3.JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)

4.不符合关注分离(Separation of Concerns)的原则

5.配置和调用方式非常混乱,而且基于事件的异步模型不友好。

axios

axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,它本身具有以下特征:

1.从浏览器中创建 XMLHttpRequest

2.支持 Promise API

3.客户端支持防止CSRF

4.提供了一些并发请求的接口(重要,方便了很多的操作)

5.从 node.js 创建 http 请求

6.拦截请求和响应

7.转换请求和响应数据

8.取消请求

9.自动转换JSON数据

数组排序

    • 冒泡排序法
      • 当前元素跟下一个元素对比
      • 把最大的逐个往后排列

 

var examplearr=[8,94,15,88,55,76,21,39];
function sortarr(arr){
    for(i=0;i<arr.length-1;i++){
        for(j=0;j<arr.length-1-i;j++){
            if(arr[j]>arr[j+1]){
                var temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }

        }
    }
    return arr;

}
sortarr(examplearr);
console.log(examplearr);

来源: www.cnblogs.com/zhouliang/p…

    • 选择排序法

      • 把当前元素分别跟后面的元素对比
      • 把最小的逐个往前排列
    • 快速排序法

      • 利用递归实现

递归方法实现裴波那契数列

function fib(n) {
  if(n==0||n==1) return 1;
  return fib(n-1) + fib(n-2);
}

面向对象

是利用对象进行编程的一种思想(Object-oriented programming,缩写:OOP)

javascript两种开发模式

  1. 面向过程
  2. 面向对象

面向对象和面向过程的区别

  • 小狗觅食(闻一闻smell、舔一舔lick、咬一咬bite)

    分别采用面向过程和面向对象来分析

    • 面向过程(主角是小狗) :

      • 先闻一闻, 然后再舔一舔, 最后再咬一咬
    • 面向对象(主角是我):

      • 我首先要有一只小狗, 它可以闻一闻食物, 可以舔一舔食物, 可以咬一咬食物。
      • 然后我对小狗说:旺财去闻一闻,旺财去舔一舔,旺财去咬一口 (指挥小狗)

对象的组成

  • 属性(变量):

    对象有什么

  • 方法(函数):

    对象能做什么

练习如何描述一个对象

  • 描述一个人
  • 描述购物车
  • QQ聊天窗口

如何创建对象

  • 字面量 var student = {id:10,name:'小明',age:18}

  • 构造函数

    var student = new Object()
    student.id = 10;
    student.name = '王铁锤';
    student.age = 18;
    

    以上两种方式的缺点:使用同一个接口创建很多对象,会产生大量的重复代码

  • 封装工厂函数
    为了减少重复代码,对上述代码进行封装\

    缺点: 无法识别对象是由谁生成的

自定义构造函数(重点)

function Student(name, age){
    this.name = name;
    this.age = age;
    this.sayName = function(){
        alert(this.name);
    }
}
var s1 = new Student("王铁锤", 18);

new调用构造函数时经历以下4步(重要):

  1. 创建一个Object对象
  2. 将构造函数的this指向这个对象
  3. 执行构造函数中的代码
  4. 返回Object对象

实例

  • 用new关键字生成的对象称为实例
  • 实例包含一个内部属性[[prototype]],指向原型对象

构造函数与普通函数的区别

唯一区别:调用方式不同

  • 任何函数,只要通过new操作符来调用,它就可以作为构造函数;
  • 而任何构造函数,如果不通过new 操作符来调用,那它跟普通函数无区别。

约定:构造函数名首字母大写

浏览器输入一个网址到页面展示页面内容的这段时间,浏览器发生了什么?

1、接收到用户输入的网址之后

2、开启一个线程来处理判断URL地址(HTTP/HTTPS)

3、调用浏览器引擎中对应的方法(webview中的loadURL加载URL地址)

4、通过DNS解析获取该网址对应的IP地址,查询浏览器的缓存(向网站目的IP发送get请求)

5、进行HTTP协议会话,浏览器客户端向web服务器发送报文

6、进入网站后台的web服务器处理请求

7、进去部署好的后端服务(接口请求)

8、服务器请求并返回响应报文

9、浏览器开始下载HTML文档(加载)

10、浏览器根据收到的HTML文件解析结构建立DOM文档树

11、页面开始解析渲染DOM,CSS根据规则解析并结合DOM树进行网页内容布局和绘制渲染,JavaScript根据DOMAPI操作DOM页面整个展示过程完成

HTTP状态码

状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:

1xx:指示信息--表示请求已接收,继续处理

2xx:成功--表示请求已被成功接收、理解、接受

3xx:重定向--要完成请求必须进行更进一步的操作

4xx:客户端错误--请求有语法错误或请求无法实现

5xx:服务器端错误--服务器未能实现合法的请求

常见状态码:

200 OK //客户端请求成功

400 Bad Request //客户端请求有语法错误,不能被服务器所理解

401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用 

403 Forbidden //服务器收到请求,但是拒绝提供服务

404 Not Found //请求资源不存在,eg:输入了错误的URL

500 Internal Server Error //服务器发生不可预期的错误

503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

Vue的双向绑定原理

Vue2.x实现数据双向绑定的原理:object.defineProperty()

采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通JavaScript对象传给Vue实例来作为它的data选项时,Vue将遍历它的属性,用Object.defineProperty将他们转为getter/setter。用户看不到getter/setter,但是在内部它们让Vue追踪依赖,在属性被访问和修改时通知变化。

Vue的数据绑定将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(Vue中是用来解析{{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化——>视图更新;视图交互变化(input)——>数据model变更双向绑定效果

getter:依赖收集;setter:派发更新 总之就是一个观察者模式

vue3.0实现数据双向绑定的原理:proxy

2.0中使用的是Object.defineProperty实现对属性的监听。缺点是一定要克隆一个新的对象进行操作,否则就会造成死循环。第二个缺点是如果有多个属性,那么就要定义多个Object.defineProperty去分别监听每一个属性。

3.0中使用了ES6中的新语法,用到了Proxy去实现监听,这样省去了克隆对象的步骤,同时不管有多少个属性只需要定义一次Proxy就可以实现多对象的监听,不同分别定义。

cookie之间的跨域

反向代理概念 

反向代理方式是指以代理服务器来接收Internet上的连接请求, 然后将请求转发给内部网络上的服务器 ,并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

反向代理服务器对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理 的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端,就像这些内容 原本就是它自己的一样。

利用nginx的方向代理来解决cookie跨域问题,其实是通过“欺骗”浏览器来实现的,通过nginx,我们可以将不同工程的cookie放到nginx域下,通过nginx反向代理就可以取到不同工程写入的cookie。其实上述场景中 $.cookie(“user”, “hjzgg”, {path: “/web”}); 中的path可以写成 “/”, 这样nginx的配置就更为简单了,如下。

       location /web1 {
            proxy_pass http://web1;
            proxy_set_header Host 127.0.0.1;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Cookie $http_cookie;
            log_subrequest on;
        }
        location /web2 {
            proxy_pass http://web2;
            proxy_set_header Host 127.0.0.1;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Cookie $http_cookie;
            log_subrequest on;
        }

单点登录

在多个系统的环境下,同一个用户登录后,就不需要在其他系统中再次登录。也就是用户登录一次之后获得所有其他系统的信任。单点登录就是解决如何产生和存储所有系统的信任,再就是怎么验证这个信任的有效性。

如何存储信任凭证?

存储的信任凭证如何得到各个系统的验证?

如何存储信任凭证?

使用cookie作为存储用户的凭证。

这个实现比较简单,就是将用户的凭证存放在cookie中,

1.用户通过用户名密码在sso服务进行认证。认证通过返回认证后的凭证

2.用户通过携带的授权的凭证请求子应用系统。验证通过就认为已经登录成功了。

优点:

实现比较简单。所有的认证信息只需要依赖于cookie就可以了。

缺点:

1.cookie不是很安全,而且用户禁止cookie后没有办法登录。

2.不支持跨域实现免密登录。

3.这种的验证要保证加密算法不被人知道,如果一旦泄露,攻击者就可以通过伪造cookie则可伪造用户身份。

type of和instance of的区别

typeof判断所有变量的类型,返回值有number,boolean,string,function,object,undefined,symbols。

typeof对于丰富的对象实例,只能返回"Object"字符串。

instanceof用来判断对象,代码形式为obj1 instanceof obj2(obj1是否是obj2的实例),obj2必须为对象,否则会报错!其返回值为布尔值。

instanceof可以对不同的对象实例进行判断,判断方法是根据对象的原型链依次向下查询,如果obj2的原型属性存在obj1的原型链上,(obj1 instanceof obj2)值为true。但是instance of判断的也不够准确比如数组是Object,所以最好的办法是Object.prototype.toString.call() 不好记可以封装下

移动端适配

1、通过媒体查询的方式即CSS3的meida queries

2、以天猫首页为代表的 flex 弹性布局

3、以淘宝首页为代表的 rem+viewport缩放

4、rem 方式 blog.csdn.net/chenjuan199…

真机调试

1.电脑和手机连接到同一个WIFI

a.台式电脑和手机同时链接一个路由器,使用同一个wifi; 

b.笔记本也可以直接启用一个wifi,手机链接笔记本wifi也可以;

2.查询本地IP地址

WIN+R,输入cmd回车,打开命令提示符,输入ipconfig,查看本地IPv4;

3.修改本地项目中IP地址

找到项目中config文件夹,下面index.js文件打开; 

找到host: ‘localhost’, 改为上面本地IPv4地址;

module.exports = {

dev: {
    host: '192.168.0.107', // 原为: hotst: 'localhost'
    }
}

4.制作二维码

借助草料二维码生成修改后项目地址的二维码,cli.im/

5.重新启动项目

重新启动项目,然后浏览器地址输入本机地址http://192.168.0.107:8080 访问项目PC端项目; 

然后,手机微信扫描二维码就可以访问啦!

移动端兼容问题

www.jianshu.com/p/cb2d8ca8c…

Vue懒加载

www.jianshu.com/p/b323dadfe…

Vue下拉刷新

blog.csdn.net/so12138/art…

深拷贝和浅拷贝

浅拷贝:将原对象或者数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用 修改引用对象会改变原有的对象

深拷贝:创建一个新对象和数组,将原对象的各项属性的值(数组上的所有元素拷贝出来,是值而不是引用,相当于开启了一个新栈内存

为什么要使用深拷贝?

我们希望在改变新的数组(对象)的时候,不改变原数组(对象)

浅拷贝只是增加了一个指针指向已经存在的内存地址。

深拷贝是增加一个指针并且申请一个新的内存,内存被改变不会影响到之前的数据

深拷贝的实现:

  1. JSON.parse(JSON.stringify(data));这个方法只能转换常见数据,像function、undefined等无法通过这种方法转换
  2. 手动循环遍历

let obj = data.map(item => item);

foreach和map的区别

一、前言

  forEach()和map()两个方法都是ECMA5中Array引进的新方法,主要作用是对数组的每个元素执行一次提供的函数,但是它们之间还是有区别的。jQuery也有一个方法$.each(),长得和forEach()有点像,功能也类似。但是从本质上还是有很大的区别的,那么我们探探究竟。

二、forEach和map语法

2.1、语法:

 //forEach 
 array.forEach(callback(currentValue, index, array){ //do something}, this)//或者array.forEach(callback(currentValue, index, array){//do something}) 
 //map
 var new_array = arr.map(callback[, thisArg]) //$.each()$(selector).each(function(index,element))//注意参数的顺序

callback: 为数组中每个元素执行的函数,该函数接收三个参数,

参数一:当前数组中元素;参数二:索引; 参数三:当前数组。

this:可选,执行会掉时候,this的指向。

2.2、区别

  2.2.1、forEach()返回值是undefined,不可以链式调用。

  2.2.2、map()返回一个新数组,原数组不会改变。

  2.2.3、没有办法终止或者跳出forEach()循环,除非抛出异常,所以想执行一个数组是否满足什么条件,返回布尔值,可以用一般的for循环实现,或者用Array.every()或者Array.some();

  2.2.4、$.each()方法规定为每个匹配元素规定运行的函数,可以返回 false 可用于及早停止循环。

三、一些栗子

3.1 在使用forEach()时候,如果数组在迭代的视乎被修改则其他元素会被跳过。因为 forEach()不会在迭代之前创建数组的副本。

3.2反转字符串

var str = '12345';
Array.prototype.map.call(str, function(x) {   //同时利用了call()方法
  return x;
}).reverse().join('');

3.3一个笔试题。

["1", "2", "3"].map(parseInt);  //结果  [1, NaN, NaN] 

如果想得到[1, 2,3]应该这么做

function returnInt(element){
  return parseInt(element,10);
}
["1", "2", "3"].map(returnInt);

这主要是因为 parseInt()默认有两个参数,第二个参数是进制数。当parsrInt没有传入参数的时候,而map()中的回调函数时候,会给它传三个参数,第二个参数就是索引,明显不正确,所以返回NaN了。  

四、兼容性

forEach()和map()是ECMA5新引入的,可能在标准的其他实现中不存在,在使用前可以要Ployfill一下。

具体网上很多吧,更多的是在ie9以下,如果你的项目无视这些,那么你可以不care。

HTML5新特性有哪些跟之前的4.1比有什么区别?

html5比html4多了十个新特性,但不支持IE8及以下版本的浏览器,

1、语义化标签,大概有header、nav、section、article、aside、footer、main

2、增强型表单

修改了input输入特性,例如color(用于选取颜色),date(选取日期)tel(定义输入电话号码和字段)

新增了5个表单元素

下拉列表、进度条、刻度值、提供一种验证用户的可靠方法生成一个公钥和私钥、用于不同类型的输出比如脚本输出

新增表单属性

placehoder:输入框默认提示文字

required:输入内容是否为空

pattern:正则表达式验证输入的值

min/max:设置元素最小/最大值

autofocus:自动获取焦点

multple:规定可选择多个值

3、audio和video标签

4、canvas绘图

5、SVG绘图

6、地理定位使用getCurrentPosition()方法来获取用户的位置

7、拖放API

8、webwoker

webwoker可以通过加载一个脚本文件,从而创建一个独立工作的线程,在主线程之外运行,起到互补阻塞的效果,并且提供主线程和新线程之间数据交互的接口:postMessage、onMessage

9、webstroage有5M的存储容量

10、websocket

CSS3的新特性?

transition、animation、transfrom、box-shadow、border-image、rgba、