整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

中高级前端面试知识点汇总

中高级前端面试知识点汇总

.1、什么是HTML语义化?有什么好处?

根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地解析。
为了在没有 CSS 的情况下,页面也能呈现出很好地内容结构、代码结构:为了裸奔时好看;
用户体验:例如 title、alt 用于解释名词或解释图片信息、label标签的活用;
有利于 SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;
方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以语义的方式来渲染网页;
便于团队开发和维护,语义化更具可读性,是下一步网页的重要动向,遵循这个标准,可以减少差异化。

1.2、html5有哪些新特性?

HTML5 已经不是 SGML 的子集
新增关于图像,地理位置,缓存,多任务等多个功能
用于媒体回放的 Video 和 Audio
语义化更好的标签如 header、footer、section、aside、nav、canvas、time等等,利于SEO优化
新增的表单元素如 <datalist>、<keygen>、<output>
新增的表单属性如 autocomplete、autofocus、placeholder、required、step等等。
HTML5 Web 存储 sessionStorage 和 localStorage
HTML5 WebSocket
HTML5 离线Web应用(应用程序缓存)

1.3、你能解释一下CSS的盒子模型么?

CSS盒模型是围绕在HTML元素周围的定义 Border(边界),padding(内边距)和

margin(外边距)的矩形空间

Border(边界):定义了元素包含的最大区域

Padding(内边距):定义了边界和内部元素的间距

Margin:定义了边界和任何相邻元素的间距

1.4、CSS选择器有哪些?哪些属性可以继承?

	CSS选择符:id选择器(#myid)、类选择器(.myclassname)、标签选择器(div, h1, p)、相邻选择器(h1 + p)、子选择器(ul > li)、后代选择器(li a)、通配符选择器(*)、属性选择器(a[rel=”external”])、伪类选择器(a:hover, li:nth-child)
可继承的属性:font-size, font-family, color
不可继承的样式:border, padding, margin, width, height
优先级(就近原则):!important > [ id > class > tag ]
!important 比内联优先级高

1.5、CSS3新增伪类有那些?

E:nth-last-child(n) 
E:nth-of-type(n) 
E:nth-last-of-type(n) 
E:last-child 
E:first-of-type 
E:only-child 
E:only-of-type 
E:empty 
E:checked 
E:enabled 
E:disabled 
E::selection 
E:not(s)
E::not(.s)
tbody: nth-child(even), nth-child(odd)/*:此处他们分别代表了表格(tbody)下面的偶数行和奇数行(tr)*/等等......

1.6、css3有那些新特性?

RGBA 和透明度

background-image background-origin(content-box/padding-box/border-box)

background-size background-repeat

word-wrap(对长的不可分割单词换行)word-wrap:break-word

文字阴影:text-shadow: 5px 5px 5px #FF0000;(水平阴影,垂直阴影,模糊距离,阴影颜色)

font-face属性:定义自己的字体

圆角(边框半径):border-radius 属性用于创建圆角

边框图片:border-image: url(border.png) 30 30 round

盒阴影:box-shadow: 10px 10px 5px #888888

媒体查询:定义两套css,当浏览器的尺寸变化时会采用不同的属性

1.7、对BFC规范(块级格式化上下文:block formatting context)的理解?

BFC规定了内部的 Block Box 如何布局。

定位方案:

内部的 Box 会在垂直方向上一个接一个放置。

Box 垂直方向的距离由 margin 决定,属于同一个BFC的两个相邻Box的margin会发生重叠。

每个元素的margin box 的左边,与包含块border box的左边相接触。

BFC的区域不会与float box重叠。

BFC是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。

计算BFC的高度时,浮动元素也会参与计算。

满足下列条件之一就可触发BFC:

根元素,即html

float 的值不为 none(默认)

overflow 的值不为 visible(默认)

display 的值为 inline-block、table-cell、table-caption

position 的值为 absolute 或 fixed

1.8、 CSS优化、提高性能的方法有哪些?

避免过度约束
避免后代选择符
避免链式选择符
使用紧凑的语法
避免不必要的命名空间
避免不必要的重复
最好使用表示语义的名字。一个好的类名应该是描述他是什么而不是像什么
避免!important,可以选择其他选择器
尽可能的精简规则,你可以合并不同类里的重复规则

1.9、两个div并排,左边div固定宽度,右边宽度自适应”,至少列出4种。

方式一:BFC(块级格式化上下文)
思路:左边定宽 float:left,右边采用 overflow: hidden; /* 触发bfc */
方式二:采用flex布局
这种应该是最简单的方式,右边 flex:1
方式三:采用 display:table的方式来实现布局
父元素 display:table,两个子元素采用 display:table-cell;
方式四:采用calc计算宽度的方式来实现
方式五:采用absolute+margin-left来实现

1.10、Sass和Less的异同之处。

1、Less 环境较 Sass简单
Cass的安装需要安装Ruby环境,Less基于JavaScript,是需要引入Less.js来处理代码输出css到浏览器,也可以在开发环节使用Less,然后编译成css文件,直接放在项目中,有less.app、SimpleLess、CodeKit.app这样的工具,也有在线编辑地址。
2、Less 使用较 Sass简单
LESS 并没有裁剪 CSS 原有的特性,而是在现有 CSS 语法的基础上,为 CSS 加入程序式语言的特性。只要你了解 CSS 基础就可以很容易上手。
3、从功能出发,Sass 较 Less 略强大一些
①sass有变量和作用域。
- $variable,like php;
- #{$variable}like ruby;
- 变量有全局和局部之分,并且有优先级。
② sass 有函数的概念;
- @function和@return以及函数参数(还有不定参)可以让你像js开发那样封装你想要的逻辑。
-@mixin类似function但缺少像function的编程逻辑,更多的是提高css代码段的复用性和模块化,这个用的人也是最多的。
-ruby提供了非常丰富的内置原生api。
③进程控制:
-条件:@if @else;
-循环遍历:@for @each @while
-继承:@extend
-引用:@import
④数据结构:
-$list类型=数组;
-$map类型=object;
其余的也有string、number、function等类型
4、Less 与Sass 处理机制不一样
前者是通过客户端处理的,后者是通过服务端处理,相比较之下前者解析会比后者慢一点
 
5、关于变量在 Less 和 Sass 中的唯一区别就是 Less 用@,Sass 用$。

###二、Javascript 部分

2.1、介绍JavaScript的基本数据类型

String、Number、Boolean、Null、Undefined、Symbol、BigInt

2.2谈谈this的理解

this 总是指向函数的直接调用者(而非间接调用者)
如果有new关键字,this 指向new 出来的那个对象
在事件中,this 指向目标元素,特殊的是IE的attachEvent中的this总是指向全局对象window。

2.3、null,undefined的区别?

null表示一个对象被定义了,但存放了空指针,转换为数值时为0。
undefined表示声明的变量未初始化,转换为数值时为NAN。
typeof(null) -- object;
typeof(undefined) -- undefined

2.4、 什么是闭包(closure),为什么要用它?

闭包指的是一个函数可以访问另一个函数作用域中变量。常见的构造方法,是在一个函数内部定义另外一个函数。内部函数可以引用外层的变量;外层变量不会被垃圾回收机制回收。
注意,闭包的原理是作用域链,所以闭包访问的上级作用域中的变量是个对象,其值为其运算结束后的最后一个值。
优点:避免全局变量污染。缺点:容易造成内存泄漏。
特性: 
a. JavaScript允许你使用在当前函数以外定义的变量 
b. 即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量 
c. 闭包可以更新外部变量的值 
d. 用闭包模拟私有方法 
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题
例子:
function makeFunc() {
 var name="Mozilla";
 function displayName() {
 console.log(name); 
 }
 return displayName;
}
var myFunc=makeFunc();
myFunc(); //输出Mozilla

2.5、如何判断一个对象是否属于某个类?

使用instanceof 即if(a instanceof Person){alert('yes');}

2.6、new操作符具体干了什么呢?

创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
属性和方法被加入到 this 引用的对象中。
新创建的对象由 this 所引用,并且最后隐式的返回 this 。

2.6、JS延迟加载的方式有哪些?

JS的延迟加载有助与提高页面的加载速度。
defer和async、动态创建DOM方式(用得最多)、按需异步载入JS
defer:延迟脚本。立即下载,但延迟执行(延迟到整个页面都解析完毕后再运行),按照脚本出现的先后顺序执行。
async:异步脚本。下载完立即执行,但不保证按照脚本出现的先后顺序执行。

2.7、call和apply的区别

call()方法和apply()方法的作用相同,动态改变某个类的某个方法的运行环境。他们的区别在于接收参数的方式不同。在使用call(obj,a1,a2...)方法时,传递给函数的参数必须逐个列举出来。使用apply(obj,[a1,a2...])时,传递给函数的是参数数组。

2.8、数组对象有哪些原生方法,列举一下

pop、push、shift、unshift、splice、reverse、sort、concat、join、slice、toString、indexOf、lastIndexOf、reduce、reduceRight、forEach、map、filter、every、some

2.9、什么是跨域?如何解决?

要明白什么是跨域之前,首先要明白什么是同源策略?
同源策略就是用来限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。那怎样判断是否是同源呢?
如果协议,端口(如果指定了)和主机对于两个页面是相同的,则两个页面具有相同的源,也就是同源。也就是说,要同时满足以下3个条件,才能叫同源:
协议相同
端口相同
主机相同
解决方案:
1.iframe
随着近年来前端技术的飞跃发展以及移动互联网时代的洗礼,iframe的使用渐渐的不被建议,虽然也是一种跨域请求的解决方案,但这里就不再讲述,请读者自行查阅网上资料。
2.jsonp
jsonp是比较常用的方法,我们假设a.com域名需要向b.com发起一个api请求(jsonp的一个缺点是,仅能接受GET方式),则使用JSONP完成该过程的。
3. 通过请求同域下的api,间接获取它域的数据
我们仍以域名a.com/demo.html需获取b.com下的数据为例,这时候只要在a.com下创建一个demo.php,由demo.php通过curl的方式向b.com发起数据请求,并包装请求结果返回给a.com/demo.html页面。这里主要是通过与a.com/demo.html同域下的a.com/demo.php做了一层数据请求代理,避免了前端跨域请求。
4.使用web服务器的反向代理设置
同样是使用代理的思维,但与2不同的是,我们这里使用web服务器的反向代理配置:
Nginx反向代理可以使用 proxy_pass
Apache2的反向代理的配置可以使用ProxyPass
5.设置header头(CORS)
在你要跨域请求的api里,设置header头Access-Control-Allow-Origin: "*";

2.10、如何实现js中的继承

1、原型继承的第一种方式:

function Cat(name){

this.name=name;

}

//原型继承

Cat.prototype.say=function(){

alert("你好,我是一只猫,我叫:"+this.name);

}

2、原型继承第二种方式:

function Cat(name) {

this.name=name;

}

function Animal() {}

Animal.prototype.run=function () {

alert("动物跑");

};

Cat.prototype=new Animal();

Cat.prototype.constructor=Cat;

3、借用构造函数

function Cat(name,age) {

Animal.call(this,name,age);

}

function Animal(name,age) {

this.name=name;

this.age=age;

}

4、经典继承

function create(obj) {

if(Object.create) {

return Object.create(obj);

} else {

function F(){};

F.prototype=obj;

return new F();

}

}

2.11、看下列代码,输出什么?解释原因。

var undefined;//此时undefined这个变量的值是undefined
undefined==null; // true
1==true; // true
此时会把布尔类型的值转换为数字类型 true=1 false=0
2==true; // false
0==false; // true
0==''; // true
NaN==NaN; // false isNaN
[]==false; // true 解释:会把[]和false都通过Number()转换为数字类型
[]==![]; // true 解释:![]:false
[]==[];//false
一个是number一个是string时,会尝试将string转换为number 
一个是number一个是boolean,将boolean转换为number,结果:true:1 false:0 
一个是object 另一个是string或number,将Object转换成number或string 
所以,对于0、空字符串的判断,建议使用 “===” 。“===”会先判断两边的值类型,类型不匹配时为false。

2.12、已知数组numberArray=[3,6,2,4,1,5];

1) 实现对该数组的倒排,输出[5,1,4,2,6,3]
function reverseArray(arr){
 var result=[];
 //方法1:
 /*for (var i=arr.length - 1; i >=0; i--) {
 result.push(arr[i]);
 }*/
 //方法2:
 for (var i=0, len=arr.length; i < len; i++) {
 result.unshift(arr[i]);
 }
 return result;
}
2) 实现对该数组的降序排列,输出[6,5,4,3,2,1] 
冒泡排序过程演示
function sortDesc(arr) {
 for (var i=0, len=arr.length; i < len; i++) {
 for (var j=i + 1, len2=arr.length; j < len2; j++) {
 //>就是降序 <就是升序
 if (arr[j] > arr[i]) {
 var temp=arr[j];
 arr[j]=arr[i];
 arr[i]=temp;
 }
 }
 }
 return arr;
}

2.13、有这样一个URL:http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e,请写一段JS程序提取URL中的各个GET参数(参数名和参数个数不确定),将其按key-value形式返回到一个json结构中,如{a:’1′, b:’2′, c:”, d:’xxx’, e:undefined}。

答案:
function serlize(url){
 var result={};
 //1、寻找?后面的字符串
 url=url.substr(url.indexOf("?")+1);
 //2、将字符串用&分隔
 var args=url.split("&");//[“a=1”,”b=2”]
 for (var i=0, len=args.length; i < len; i++) {
 var arg=args[i];
 var item=arg.split('=');
 //3、对象的键=值
 result[item[0]]=item[1];
 }
 return result;
}
serlize(‘http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e‘);

2.14、什么是 Javascript 高阶函数?并写出例子

如果一个函数操作其他函数,即将其他函数作为参数或将函数作为返回值,则称这个函数是一个高阶函数。

我们来看看下面的例子:

function abc(temp){

console.log(temp);

}

function def(temp1,temp2){

temp1(temp2);

}

def(abc,"sos");

执行之后,输出:sos

首先我们定义了两个函数 abc() 和 def() ,

然后执行 def(abc,"sos"),我们把abc 这个函数作为了函数def() 的一个参数,

最后在函数def 中执行了 abc() 这个函数;

2.15、JavaScript 什么是原型链?

原型链 : 实例对象与原型之间的链接,叫做原型链
 Function.prototype.a="a";
 Object.prototype.b="b";
 function Person(){}
 console.log(Person); //function Person()
 let p=new Person();
 console.log(p); //Person {} 对象
 console.log(p.a); //undefined
 console.log(p.b); //b
 想一想p.a打印结果为undefined,p.b结果为b
 解析:
 p是Person()的实例,是一个Person对象,它拥有一个属性值__proto__,并且__proto__是一个对象,包含两个属性值constructor和__proto__。
console.log(p.__proto__.constructor); //function Person(){}
console.log(p.__proto__.__proto__); //对象{},拥有很多属性值
我们会发现p.__proto__.constructor返回的结果为构造函数本身,
p.__proto__.__proto__有很多参数
我们调用constructor属性,p.___proto__.__proto__.constructor得到拥有多个参数的Object()函数,Person.prototype的隐式原型的constructor指向Object(),即Person.prototype.__proto__.constructor==Object()
从p.__proto__.constructor返回的结果为构造函数本身得到Person.prototype.constructor==Person()所以p.___proto__.__proto__==Object.prototype
所以p.b打印结果为b,p没有b属性,会一直通过__proto__向上查找,最后当查找到Object.prototype时找到,最后打印出b,向上查找过程中,得到的是Object.prototype,而不是Function.prototype,找不到a属性,所以结果为undefined,这就是原型链,通过__proto__向上进行查找,最终到null结束
console.log(p.__proto__.__proto__.__proto__); //null
console.log(Object.prototype.__proto__); //null
 大家理解刚才的过程,相信下面这些应该也都明白
//Function
function Function(){}
console.log(Function); //Function()
console.log(Function.prototype.constructor); //Function()
console.log(Function.prototype.__proto__); //Object.prototype
console.log(Function.prototype.__proto__.__proto__); //NULL
console.log(Function.prototype.__proto__.constructor); //Object()
console.log(Function.prototype.__proto__===Object.prototype); //true
总结:
1.查找属性,如果本身没有,则会去__proto__中查找,也就是构造函数的显式原型中查找,如果构造函数中也没有该属性,因为构造函数也是对象,也有__proto__,那么会去它的显式原型中查找,一直到null,如果没有则返回undefined
2.p.__proto__.constructor==function Person(){}
3.p.___proto__.__proto__==Object.prototype
4.p.___proto__.__proto__.__proto__==Object.prototype.__proto__==null 
5.通过__proto__形成原型链而非protrotype
最后附上一张图,大家阅读完之后,看图应该可以很容易理解

###三、ES6、ES7、ES8 的相关知识点

ES6
块级作用域 关键字let, 常量const
对象属性赋值简写(property value shorthand)
解构赋值
函数参数 - 默认值、参数打包、 数组展开(Default 、Rest 、Spread)
箭头函数 (Arrow functions)
字符串模板 Template strings ${}
迭代器(Iterators)for (var n of ['a','b','c'])
生成器 (Generators)
class、constructor、extends、super
Modules(模块)
具有CommonJS的精简语法、唯一导出出口(single exports)和循环依赖(cyclic dependencies)的特点。
类似AMD,支持异步加载和可配置的模块加载。
Map + Set + WeakMap + WeakSet
WeakMap、WeakSet作为属性键的对象如果没有别的变量在引用它们,则会被回收释放掉。
Math + Number + String + Array + Object APIs
Proxies:使用代理(Proxy)监听对象的操作
.Symbols:调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。
!!!Promises:处理异步操作的对象,用链式调用组织代码
var promise=new Promise((resolve, reject)=> {
 this.login(resolve)
}) //链式调用
.then(()=> this.getInfo())
.catch(()=> { console.log("Error") })
4.ES7
求幂运算符(**)
3 ** 2 // 9
等价于:
Math.pow(3, 2) // 9
Array.prototype.includes()方法:不能比较复杂类型数据,查找一个值在不在数组里,若在,则返回true,反之返回false。
['a', 'b', 'c'].includes('a') // true
等价于
['a', 'b', 'c'].indexOf('a') > -1 //true
函数作用域中严格(strict)模式的变更。
装饰器(Decorator):修改类的行为
参数:target(所要修饰的目标类), name(所要修饰的属性名), descriptor(该属性的描述对象)
使用:npm install core-decorators –save
// 将某个属性或方法标记为不可写。
@readonly 
// 标记一个属性或方法,以便它不能被删除; 也阻止了它通过Object.defineProperty被重新配置
@nonconfigurable 
// 立即将提供的函数和参数应用于该方法,允许您使用lodash提供的任意助手来包装方法。 第一个参数是要应用的函数,所有其他参数将传递给该装饰函数。
@decorate 
// 如果你没有像Babel 6那样的装饰器语言支持,或者甚至没有编译器的vanilla ES5代码,那么可以使用applyDecorators()助手。
@extendDescriptor
// 将属性标记为不可枚举。
@nonenumerable
// 防止属性初始值设定项运行,直到实际查找修饰的属性。
@lazyInitialize
// 强制调用此函数始终将此引用到类实例,即使该函数被传递或将失去其上下文。
@autobind
// 使用弃用消息调用console.warn()。 提供自定义消息以覆盖默认消息。
@deprecate
// 在调用装饰函数时禁止任何JavaScript console.warn()调用。
@suppressWarnings
// 将属性标记为可枚举。
@enumerable
// 检查标记的方法是否确实覆盖了原型链上相同签名的函数。
@override 
// 使用console.time和console.timeEnd为函数计时提供唯一标签,其默认前缀为ClassName.method。
@time
// 使用console.profile和console.profileEnd提供函数分析,并使用默认前缀为ClassName.method的唯一标签。
@profile
@noConcurrent 避免并发调用,在上一次操作结果返回之前,不响应重复操作
@makeMutex 多函数互斥,具有相同互斥标识的函数不会并发执行
@withErrToast 捕获async函数中的异常,并进行错误提示
@mixinList 用于分页加载,上拉加载时返回拼接数据及是否还有数据提示
@typeCheck 检测函数参数类型
import {noConcurrent} from './decorators';
methods: {
 @noConcurrent //避免并发,点击提交后,在接口返回之前无视后续点击
 async onSubmit(){
 let submitRes=await this.$http({...});
 //...
 return;
 }
}
methods: {
 @mixinList({needToast: false})
 async loadGoods(params={}){
 let goodsRes=await this.$http(params);
 return goodsRes.respData.infos;
 },
 async hasMore() {
 let result=await this.loadgoods(params);
 if(result.state==='nomore') this.tipText='没有更多了';
 this.goods=result.list;
 }
}
// 上拉加载调用hasMore函数,goods数组就会得到所有拼接数据
// loadGoods可传三个参数 params函数需要参数 ,startNum开始的页码,clearlist清空数组
// mixinList可传一个参数 needToast 没有数据是否需要toast提示 
5.ES8
异步函数(Async function)使用形式:
函数声明: async function foo() {}
函数表达式: const foo=async function() {}
对象的方式: let obj={ async foo() {} }
箭头函数: const foo=async ()=> {}
this.$http.jsonp('/login', (res)=> {
 this.$http.jsonp('/getInfo', (info)=> {
 // do something
 })
})
异步编程机制:Generator async/await
function * 函数名(){ 
 yieId 'hello';
 yieId 'world';
 return 'ending';
}
var hs=函数名(); 
hs.next();
// { value: 'hello', done: false }
hs.next();
// { value: 'world', done: false }
hs.next();
// { value: 'ending', done: true }
hs.next();
// { value: undefined, done: true } 
//自动执行Generator函数
async function asyncFunc(params) {
 const result1=await this.login()
 const result2=await this.getInfo()
}
调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,必须调用遍历器对象的next方法,使得指针移向下一个状态。每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。
yieId:(产出),分段执行,yield表达式是暂停执行的标记,而next方法可以恢复执行
Object.entries()和Object.values()
(1)Object.entries():具有键值对的数据结构,则每一个键值对都将会编译成一个具有两个元素的数组,这些数组最终会放到一个数组中,返回一个二维数组,若目标对象是数组时,则会将数组的下标作为键值返回。键值对中,如果键的值是Symbol,编译时将会被忽略
Object.entries({ one: 1, two: 2 }) //[['one', 1], ['two', 2]]
Object.entries([1, 2]) //[['0', 1], ['1', 2]]
如果对象的key值是数字,则返回值会对key值进行排序,返回的是排序后的结果。
Object.entries({ 3: 'a', 4: 'b', 1: 'c' }) //[['1', 'c'], ['3', 'a'], ['4', 'b']]
 
//对象属性的遍历
let obj={ one: 1, two: 2 };
for (let [k,v] of Object.entries(obj)) {
 console.log(`${JSON.stringify(k)}: ${JSON.stringify(v)}`);
} 
//输出结果如下:
'one': 1
'two': 2
(2)Object.values():只返回自己的键值对中属性的值
Object.values({ one: 1, two: 2 }) //[1, 2]
Object.values({ 3: 'a', 4: 'b', 1: 'c' }) //['c', 'a', 'b']
字符串填充:padStart和padEnd
padStart函数:通过填充字符串的首部来保证字符串达到固定的长度,默认情况下使用空格填充
padEnd:填充字符串的尾部来保证字符串的长度的。
'Vue'.padStart(10) //' Vue'
'Vue'.padStart(10, '_*') //'_*_*_*_Vue' 
'Vue'.padEnd(10, '_*') //'Vue_*_*_*_'
Object.getOwnPropertyDescriptors():返回目标对象中所有属性的属性描述符,该属性必须是对象自己定义的,不能是从原型链继承来的。
该方法返回的描述符,会有两种类型:数据描述符、存取器描述符
返回结果中包含的键可能的值有:configurable、enumerable、value、writable、get、set。
let obj={
 id: 1,
 name: 'test',
 get gender() {
 console.log('gender')
 },
 set grade(g) {
 console.log(g)
 }
}
Object.getOwnPropertyDescriptors(obj, 'id') 
//输出结果为:
{
 id: {
 configurable: true,
 enumerable: true,
 value: 1,
 writable: true
 }
} 
和assign区别
Object.assign(obj) 
//输出结果为:
{
 gender: undefined
 id: 1,
 name: 'test'
}
共享内存和原子(共享阵列缓冲区,Shared memory and atomics)笔记待完善
新的构造函数SharedArrayBuffer、具有辅助函数的命名空间对象Atomics
多线程并发读写数据
添加尾部逗号而不报错

###四、前端性能优化

1、雪碧图技术
这个很简单,把每个小图标都整合到一张大图上面,极大的减轻http请求数,同时能够让图片快速加载进来。
考虑到当前的5g的发展前景,以后图片不会造成加载延迟的现象。
2、浏览器渲染机制
输入一个网址:我们得到服务端html文件。
根据html文件,从头到尾的一个个的依次渲染页面渲染页面。
但是遇到图片——不会等待图片的加载完毕,会直接渲染下面的标签。
如果图片加载出来——根据图片选择,由于图片要占用空间,决定是否重新加载页面,这个概念叫reflow。(优化的方式——给图片宽高)。
reflow和什么相关:占位面积、定位方式、边距。
对于样式中的颜色变化,叫做repaint、这个就只需要把颜色改变。所以性能上来说,repaint稍微比reflow高点。
repaint和什么相关:和颜色变化相关
3、webpack、gulp等打包工具的使用
压缩代码,减少了代码体积。
可以把多个css文件,多个js文件,合并为一个css文件/js文件。
合并文件,让我们减少了http请求数。
4、避免页面跳转,也就是使用单页面应用的开发。
每次页面跳转,就是一次html文件的下载过程。而这个过程,我们首先从服务端下载网页,再进行渲染,网页性能体验会很差。而单页面应用,它从一开始,就把完整的网页给加载到本地。
5、延迟加载、懒加载技术
什么是懒加载技术:
原理:先将img标签中的src链接设为同一张图片(空白图片),将其真正的图片地址存储再img标签的自定义属性中(比如data-src)。当js监听到该图片元素进入可视窗口时,即将自定义属性中的地址存储到src属性中,达到懒加载的效果。
这样做能防止页面一次性向服务器响应大量请求导致服务器响应慢,页面卡顿或崩溃等问题。
6、将css放在HEAD中
如果将 CSS放在其他地方比如 BODY中,则浏览器有可能还未下载和解析到 CSS就已经开始渲染页面了,这就导致页面由无 CSS状态跳转到 CSS状态,用户体验比较糟糕。除此之外,有些浏览器会在 CSS下载完成后才开始渲染页面,如果 CSS放在靠下的位置则会导致浏览器将渲染时间推迟。
7、Vue项目的按需加载
vue中的懒加载是通过webpack的代码分割来实现的,下面是官网文档:https://router.vuejs.org/zh-cn/advanced/lazy-loading.html
主要是在加载路由的时候,使用: 
const Main=r=> require.ensure([], ()=> r(require(‘../views/main/Main’)))
require.ensure就是webpack提供的异步加载的方式。
8、关于React的性能优化
react中,进行性能优化的核心就是shouldComponentDidMount周期函数。 
9、设置合理的http缓存
http请求中,我们可以合理的设置headers,就能达到缓存的目的。
有两种常见的缓存,强制缓存和对比缓存:
第一种:强制缓存。 
直接访问浏览器中的缓存数据,如果存在,则直接使用浏览器中的数据。如果不存在,则再向服务器发送请求,然后得到服务器的数据,再把这些数据存在浏览器中。
第二种:对比缓存。 
首先,获取浏览器中的数据缓存标识,再获取服务器上面的数据缓存标识,如果相匹配,则直接从浏览器中获取数据,如果不匹配,则从服务器上获取数据。
关于缓存标识,有两类标识:
第一类: 
第一次请求,服务器会返回一个Last-Modified。 
下一次请求,浏览器会自动在headers中添加一条If-Modified-Since属性,记录的就是上一次数据发生修改的时间。
第二类: 
第一次请求,服务端返回一个Etag资源唯一标识符。 
第二次请求,浏览器会自动携带一个If-None_Match标识符。
应用程序缓存
创建cache manifest文件,通过给html文件中的HTML标签添加一个manifest属性来实现的。
<!DOCTYPE HTML>
<html manifest="demo.appcache">
<body>
	文档内容......
</body>
</html>

###五、Vue、React、Angular 的异同点

1、Angular特性:
由自己实现一套模板编译规则,数据变化依赖脏检查,
基本属性包括:数据双向绑定、基本模板指令、自定义指令、表单验证、路由操作、依赖注入、过滤器、内置服务、自定义服务、组件、模块。
运行效率较低,数据变更检测方式。
学习angular会迫使你学习特有的预发,上手成本很大,代码看起来很干净
依赖注入,即一个对象将依赖项提供给另一个对象(客户端)的模式。导致更多的灵活性和更干净的代码。
Angular 最适合单页应用(SPA),因为它可能太臃肿而不能用于微服务。
框架比较臃肿,每次用啥功能要引入一大堆东西
Angular错误提示不够清晰明显,对于初级开发者,很难看懂Angular的错误提示。(个人认为这是最大的不好之处,当初学习这个遇到很多坑啊),而且定位bug很难。
面向对象编程的思想,Angular由后端开发人员设计的前端框架。
详细比较:React和Vue的区别
2、React特性:
单向绑定,先更新model,然后渲染UI元素,数据在一个方向流动,使得调试更加容易。代码冗余,各种生命周期太麻烦,刚开始接触好难记。
用了虚拟DOM。(对虚拟DOM的理解刚开始我不是很理解概念,建议大家去看【深入REACT技术栈】这本书有很好的讲解)
更适合大型应用和更好的可测试性
Web端和移动端原生APP通吃
更大的生态系统,更多的支持和好用的工具
3、Vue特性
模板和渲染函数的弹性选择
简单的语法和项目配置
更快的渲染速度和更小的体积四
4、Vue和React共同点
用虚拟DOM实现快速渲染
轻量级
响应式组件
服务端渲染
集成路由工具,打包工具,状态管理工具的难度低
5:不同点
vue 控制器:无;过滤器 :无 ;指令:有;渲染指令: 有 ;数据绑定:双向;
React 控制器:无;过滤器 :无 ;指令:无;渲染指令 : 无 ;数据绑定:单向;
angular 控制器:有;过滤器 :有 ;指令:有;渲染指令 : 有 ;数据绑定:双向;

###六、Webpack 如何对项目构建优化

请移驾我的另一篇 Chat 文章https://gitbook.cn/gitchat/activity/5bed34555748cb6bd2780d4b

###七、首屏优化

1. DNS预解析
2.域名收敛
既然DNS解析比较耗时,每个连接都要建立链路,那么我们就可以通过减少ajax到后台的域名地址,通过反向代理去做。
3. 链路复用
因为每一次链接数都要建立3次TCP握手,通过keep-alive,可以保证建立的连接不会被关闭, 下次请求可以直接发送数据,这样可以减少将近200ms的时间,当然会增加一部分Server的内存消耗,要预先扩容;http2.0已经支持了这些特性;
4. 资源内联
在首屏里,一些资源都是分散开发的,在一些简单的页面中,有些内容可以内联进去,不然像一些css页面要等到html页面解析完成后,再去解析外联的css; 可以通过打包工具在发布的时候就能完成;
5.组件化开发
首先一点是按需加载,就是首屏显示的东西,哪些要加载,哪些无需加载,可以区分开来,而且可以异步方式来加载。
我们通常是这么做的,我们可以先加载一些公用的东西,然后通过路由,去加载首屏上可以看到选项卡的资源,哪些有用户交互之后的东西,可以稍后在加载;
但是这样会有一个问题,有时候我们的js处理的比较快,但是css文件处理的比较快,这样就会使的页面比较混乱,所以可以通过异步打包工具,将css和js打包在一起
6. 服务端渲染
一个前后端分离的项目,通过ajax请求数据,这样一个页面的渲染路径会拉的很长,页面先渲染html,然后在渲染js,js才发送ajax请求,等到数据回来再进行渲染,所以不管怎么样都至少要3个RTT请求时间;这种模式,在网络环境比较差的情况下,是很难接受的,
所以我们又回归到PHP时代;通过服务器端渲染,就可以控制用户,哪些东西是要打包的。可以一次性知道用户需要哪些数据;加上现在的NodeJs环境以及React,这就使得一些东西既可以在前端的浏览器进行渲染,也可以在服务器中进行字符串拼接,一起吐出来;
比如在无限长的滚动列表中,对图片进行懒加载,首先不给图片赋值src属性,通过插入dom计算可视区,在可视区内则赋值src,在可视区之外,交给scroll去处理,将要进入可视区时才赋值;
7.利用缓存
资源长缓存:不是通过304去判断缓存,而是通过max-age来做的,通过md5命名文件,然后通过自动化构建工具去实现;主要聊一下数据层缓存与数据复用;
从客户端的启发;客户端会将上次缓存的数据重新渲染一遍;所以数据缓存的设计可以设计为
可以在ajax请求的数据没有回来之前,用一些配置的假数据,先把坑站好,然后等待线上的数据回来后,在把坑填好,这样减少了白屏的时间。这样给用户感觉比较快,但不是真的快,交互性能确实变好了;
在有些时候,并不是所有的数据都是加载进来的,像贴吧和知乎之类的,展示的一些storage里的数据,都是带有省略号的缓存数据,等用户真的点开之后才去加载该帖子的全部数据。每次请求的数据又重新将原来的缓存覆盖;
8.离线包
其实对于一些并发量比较大,向过年时候的抢红包业务,并发量是几个亿。这样,对于一些经常使用的用户,可以几天前就将离线包推送过去,进行下载,通过二进制比较,进行动态增量更新,而不用每次都下载,这么大的并发量,同时下载,带宽肯定爆,服务器肯定爆。
9.减少请求次数
10.减少对dom的操作

###七、移动端如何做适配

现在最常用的就是一稿设计多端适配方案—— rem + flexible
rem是什么?
rem(font size of the root element)是指相对于根元素的字体大小的单位。简单的说它就是一个相对单位。看到rem大家一定会想起em单位,em(font size of the element)是指相对于父元素的字体大小的单位。它们之间其实很相似,只不过一个计算的规则是依赖根元素一个是依赖父元素计算。
REM自适应JS
//designWidth:设计稿的实际宽度值,需要根据实际设置
//maxWidth:制作稿的最大宽度值,需要根据实际设置
//这段js的最后面有两个参数记得要设置,一个为设计稿实际宽度,一个为制作稿最大宽度,例如设计稿为750,最大宽度为750,则为(750,750)
;(function(designWidth, maxWidth) {
	var doc=document,
	win=window,
	docEl=doc.documentElement,
	remStyle=document.createElement("style"),
	tid;
	function refreshRem() {
		var width=docEl.getBoundingClientRect().width;
		maxWidth=maxWidth || 540;
		width>maxWidth && (width=maxWidth);
		var rem=width * 100 / designWidth;
		remStyle.innerHTML='html{font-size:' + rem + 'px;}';
	}
	if (docEl.firstElementChild) {
		docEl.firstElementChild.appendChild(remStyle);
	} else {
		var wrap=doc.createElement("div");
		wrap.appendChild(remStyle);
		doc.write(wrap.innerHTML);
		wrap=null;
	}
	//要等 wiewport 设置好后才能执行 refreshRem,不然 refreshRem 会执行2次;
	refreshRem();
	win.addEventListener("resize", function() {
		clearTimeout(tid); //防止执行两次
		tid=setTimeout(refreshRem, 300);
	}, false);
	win.addEventListener("pageshow", function(e) {
		if (e.persisted) { // 浏览器后退的时候重新计算
			clearTimeout(tid);
			tid=setTimeout(refreshRem, 300);
		}
	}, false);
	if (doc.readyState==="complete") {
		doc.body.style.fontSize="16px";
	} else {
		doc.addEventListener("DOMContentLoaded", function(e) {
			doc.body.style.fontSize="16px";
		}, false);
	}
})(750, 750);
第一个参数是设计稿的宽度,一般设计稿有640,或者是750,你可以根据实际调整
第二个参数则是设置制作稿的最大宽度,超过750,则以750为最大限制。
在小王待过的公司里面,设计稿都是按750来设计的。不过管它用什么尺寸来设计,适配理念都一样,以不变应万变。
使用1rem=100px转换你的设计稿的像素,例如设计稿上某个块是100px*300px,换算成rem则为1rem*3rem。
这样子不管什么类型的手机,就都可以是适配了。像那种用多媒体查询针对不同设备尺寸写样式的方式,就让见鬼去吧。

###八、跨终端如何做适配

先来个图压压惊,图有点老,现在都iPhonx了。

如果要适配这么多设备是不是很头疼!!!

###九、MVVM 框架的知识点。

####Vue 部分

Vue组件之间如何通信
一. 父子之间的通信
1. 父组件-》子组件(props down)
①通过属性
步骤1:父组件在调用子组件时传值
<son myName="michael" myPhone='123'></son> <son :myName="userList[0]"></son>
步骤2:子组件通过props得到父组件的传过来的数据
Vue.component('son',{ props:['myName','myPhone'] })	
②通过$parent
直接在子组件中通过this.$parent得到调用子组件的父组件	
2、子组件-》父组件(events up)
①events up
步骤1:在父组件中 调用子组件的时候 绑定一个自定义事件 和 对应的处理函数
methods:{ recvMsg:function(msg){ //msg就是传递来的数据 } }, template:' <son @customEvent="recvMsg"></son> '
步骤2:在子组件中 把要发送的数据通过触发自定义事件传递给父组件
this.$emit('customEvent',123)	
② $refs
步骤1:在调用子组件的时候 可以指定ref属性
`<son ref='zhangsan'></son>`
步骤2:通过$refs
得到指定引用名称对应的组件实例
this.$refs.zhangsan
二、兄弟组件间的通信
步骤1:创建一个Vue的实例 作为事件绑定触发的公共的对象
var bus=new Vue();
步骤2:在接收方的组件 绑定 自定义的事件
bus.$on('customEvent',function(msg){ console.log(msg);	//msg是通过事件传递来的数据 (传递来的123) });
步骤3:在发送方的组件 触发 自定义的事件
bus.$emit('customEvent',123);
除了以上几种方式外,还有 Vuex、路由传参和缓存。
二、Vue的双向数据绑定原理是什么?
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter
这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
三、详细说下你对vue生命周期的理解?
总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后
创建前/后: 在beforeCreated阶段,vue实例的挂载元素$el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,$el还没有。
 
载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
 
更新前/后:当data变化时,会触发beforeUpdate和updated方法。
 
销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
四、你是怎么理解vuex的?
vuex可以理解为一种开发模式或框架。
通过状态(数据源)集中管理驱动组件的变化(好比spring的IOC容器对bean进行集中管理)。
应用级的状态集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中。
五、聊聊你对Vue.js的template编译的理解?
简而言之,就是先转化成AST树,再得到的render函数返回VNode(Vue的虚拟DOM节点)
首先,通过compile编译器把template编译成AST语法树(abstract syntax tree 即 源代码的抽象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以创建编译器的。另外compile还负责合并option。
然后,AST会经过generate(将AST语法树转化成render funtion字符串的过程)得到render函数,render的返回值是VNode,VNode是Vue的虚拟DOM节点,里面有(标签名、子节点、文本等等)

####React 部分

一、react生命周期及相关用法
react生命周期分为初始化阶段、运行阶段、销毁阶段。
(1) 初始化阶段:
getDefaultProps:获取实例的默认属性
getInitialState:获取每个实例的初始化状态
componentWillMount:实例挂载之前
Render:渲染组件
componentDidMount:实例挂载完成。一般在这个函数中与后台进行初始化数据交互。
(2)运行阶段:
componentWillReceiveProps:父组件改变时调用。
sholudComponentUpdate:主要是用来手动阻止组件渲染,一般在这个函数中做组件的性能优化。
componentWillUpdate:组件数据更新前调用
componentDidUpdate:组件数据更新完成时调用
(3)销毁阶段:
componentUnmount:销毁阶段。一般用来销毁不用的变量或者是解除无用定时器以及解绑无用事件。防止内存泄漏问题。
二、你了解 Virtual DOM 吗?解释一下它的工作原理。
Virtual DOM 是一个轻量级的 JavaScript 对象,它最初只是 real DOM 的副本。它是一个节点树,它将元素、它们的属性和内容作为对象及其属性。 React 的渲染函数从 React 组件中创建一个节点树。然后它响应数据模型中的变化来更新该树,该变化是由用户或系统完成的各种动作引起的。
Virtual DOM 工作过程有三个简单的步骤。
1.每当底层数据发生改变时,整个 UI 都将在 Virtual DOM 描述中重新渲染。
2.然后计算之前 DOM 表示与新表示的之间的差异。
3.完成计算后,将只用实际更改的内容更新 real DOM。
三、总结一下Redux的三大原则和数据流的管理
Redux三大原则:
1、单一数据源,这个应用的state被存储在一棵object tree中,并且这个object tree只存在于唯一的Store中。
2、state是只读的,唯一改变state的方法就是触发action,action是一个用于描述已发生事件的普通对象。
3、使用纯函数来执行修改,为了描述action如何改变state tree,需要编写reducer。
4、具体工作步骤如下:

Redux数据流的管理:

1、action:把数据传递到Store,唯一数据来源。

2、reducer:action只描述有事情发生,reducer指明如何更新state,即设计state结构和action处理。

3、Store:把action和reducer联系到一起,负责维持、获取和更新state。

4、生命周期:数据流严格且单向

调用Store.dispatch(action)->Store调用传入的reducer函数,Store会把两个参数传入reducer:当前的state树和action->根reducer将多个子reducer输出合并成一个单一的state树->Store保存了根reducer,并返回完整的state树。

四、Redux与它的中间件

redux是一个可预测的状态容器,

react-redux是将store和react结合起来,使得数据展示和修改对于react项目而言更简单

redux中间件就是在dispatch action前对action做一些处理

redux-thunk用于对异步做操作

redux-actions用于简化redux操作

redux-promise可以配合redux-actions用来处理Promise对象,使得异步操作更简单

redux-sage可以起到一个控制器的作用,集中处理边际效用,并使得异步操作的写法更优雅。

//这里还需要大家自己再去多了解一下redux中间件的知识。

###十、实现一个观察者模式

举个生活比较常见常见的例子,比如你去面试之后,面试官看你表现不错,最后会跟你要联系方式,以便之后可以联系你。在这角色扮演当中,你就是“订阅者”,面试官就是“发布者”。
那么发布订阅模式是咋实现的呢?
思路:
给定一个发布者
面试者将联系方式给发布者
发布者的一个列表有各种职位(web端的,java 的),里面记载回调函数以便通知这些面试者
最后发布消息的时候,会遍历这个列表的职位的回调函数,告诉面试者面试这个职位是通过还是不通过
如果面试者取消了订阅,那么将回调函数和之前的回调函数作对比,如果相等,就将这个面试者的上班通知去掉
var Event=(function() {
 var events={}; //发布者
 
 //subscribe也就是订阅,post 代表面试者要面的职位,callback表示为回调函数
 function subscribe(post, callback) {
 events[post]=events[post] || []; //发布者的列表里有没有这个面试职位,如果没有就创建一个空数组
 events[post].push(callback);
 }
 
 //publish 表示发布
 function publish() {
 var post=Array.prototype.shift.call(arguments); //第一个参数指定“键”
 var fns=events[post]; //设置缓存,提高性能
 if (!fns) { //如果发布者的列表里没有这个职位,那肯定是不能发布
 return;
 }
 for (var i=0; i < fns.length; i++) { //遍历当前的职位的数组里有几个面试者
 fns[i].apply(this, arguments);
 }
 }
 
 //unsubscribe 表示取消订阅
 function unsubscribe(post, fn) {
 var fns=events[post];
 if (fns) {
 if (fn) {
 for (var i=fns.length; i >=0; i--) {
 if (fns[i]===fn) fns.splice(i, 1);
 }
 } else {//如果没有传入fn回调函数,直接取消post对应消息的所有订阅
 fns=[];
 }
 } else {//如果发布者的列表没有这个职位,直接 return
 return;
 }
 }
 
 return {
 subscribe: subscribe,
 publish: publish,
 unsubscribe: unsubscribe
 };
})();
测试:
var fn1=function(time) {
 console.log("小明你通过了面试,上班时间:" + time);
};
var fn2=function(time) {
 console.log("小强你通过了面试,上班时间:" + time);
};
//小明将联系方式给了发布者,发布者(hr)觉得小明不错,可以通过,于是在列表(java)里写下了一些回调函数,到时候发布的时候将上班时间告诉小明
Event.subscribe("java", fn1);
//小强也订阅了
Event.subscribe("java", fn2);
 
Event.publish("java", "2017-10-01");
 
 
/*输出:
小明你通过了面试,上班时间:2017-10-01
小强你通过了面试,上班时间:2017-10-01
*/
 
Event.unsubscribe("java", fn1);//删除小明的上班通知
Event.publish("java", "2017-10-01");
 
/*输出:
小强你通过了面试,上班时间:2017-10-01
*/

###十一、实现一个数组去重的函数

//其实数组去重的方法有好多种,这就介绍常用的几种就够了
第一种:
let arr=[1, 'a', 'a', 'b', 'd', 'e', 'e', 1, 0, 2, 2, 3];
function unique(arr){
 return [...(new Set(arr))];
}
console.log(unique(arr)); // [1, "a", "b", "d", "e", 0, 2, 3]
第二种:
let arr=[1, 'a', 'a', 'b', 'd', 'e', 'e', 1, 0, 2, 2, 3];
function unique(arr){
 return Array.from(new Set(arr));
}
console.log(unique(arr)); // [1, "a", "b", "d", "e", 0, 2, 3]
第三种:
let arr=[1, 'a', 'a', 'b', 'd', 'e', 'e', 1, 0, 2, 2, 3];
function unique(arr){
 return arr.reduce((prev,cur)=> prev.includes(cur) ? prev : [...prev,cur],[]);
}
console.log(unique(arr)); // [1, "a", "b", "d", "e", 0, 2, 3]
第四种:最普通的一种,想了解更多,自己多多研究吧。
let arr=[1, 'a', 'a', 'b', 'd', 'e', 'e', '1', 0, 2, 2, 3];
function unique(arr){
 let newArr=[];
 let obj={};
 for (let i=0; i < arr.length; i++) {
 if (!obj[typeof arr[i] + arr[i]]) {
 obj[typeof arr[i] + arr[i]]=1;
 newArr.push(arr[i]);
 }
 }
 return newArr;
}
console.log(unique(arr)); // [1, "a", "b", "d", "e", "1", 0, 2, 3]

###十二、介绍Promise的原理

在Promise的内部,有一个状态管理器的存在,有三种状态:pending、fulfilled、rejected。
  (1) promise 对象初始化状态为 pending。
  (2) 当调用resolve(成功),会由pending=> fulfilled。
  (3) 当调用reject(失败),会由pending=> rejected。
  因此,看上面的的代码中的resolve(num)其实是将promise的状态由pending改为fulfilled,然后向then的成功回掉函数传值,reject反之。但是需要记住的是注意promsie状态 只能由 pending=> fulfilled/rejected, 一旦修改就不能再变(记住,一定要记住,下面会考到)。
  当状态为fulfilled(rejected反之)时,then的成功回调函数会被调用,并接受上面传来的num,进而进行操作。promise.then方法每次调用,都返回一个新的promise对象 所以可以链式写法(无论resolve还是reject都是这样)。
Promise也是面试必问的一个知识点,多多学习。  

###十三、JavaScript对象的浅拷贝与深拷贝实例分析

1、浅拷贝

仅仅复制对象的引用,而不是对象本身

var person={

name: 'Alice',

friends: ['Bruce', 'Cindy']

}

var student={

id: 30

}

student=simpleClone(person, student);

student.friends.push('David');

function simpleClone(oldObj, newObj) {

var newObj=newObj || {};

for (var i in oldObj)

newObj[i]=oldObj[i];

return newObj;

}

console.log(person.friends);//["Bruce", "Cindy", "David"]

2、深拷贝

把复制的对象所引用的全部对象都复制一遍,能够实现真正意义上的数组和对象的拷贝。

浅拷贝的问题:如果父对象的属性值为一个数组或另一个对象,那么实际上子对象获得的只是一个内存地址,而不是对父对象的真正拷贝,因此存在父对象被篡改的可能。

方法1:

var person={

name: 'Alice',

friends: ['Bruce', 'Cindy']

}

var student={

id: 30

}

student=deepClone(person, student);

student.friends.push('David');

function deepClone(oldObj, newObj) {

var newObj=newObj || {};

newObj=JSON.parse(JSON.stringify(oldObj));

return newObj;

}

console.log(person.friends); // 'Bruce', 'Cindy'

方法2:

function deepClone(oldObj, newObj) {

var newObj=newObj || {};

for (var i in oldObj) {

var prop=oldObj[i];

if (prop===newObj)

continue;

if (typeof prop==='object')

newObj[i]=(prop.constructor===Array) ? [] : Object.create(prop);

else

newObj[i]=prop;

}

return newObj;

}

###十四、彻底弄清 Callback、Promise、Generator以及Async/await

一、回调函数
所谓回调函数(callback),就是把任务分成两步完成,第二步单独写在一个函数里面,等到重新执行这个任务时,就直接调用这个函数。
例如Node.js中读取文件
fs.readFile('a,txt', (err,data)=>{
 if(err) throw err;
 console.log(data);
})
上面代码中readFile的第二个参数就是回调函数,等到读取完a.txt文件时,这个函数才会执行。
二、Promise
使用回调函数本身没有问题,但有“回调地狱”的问题。
假定我们有一个需求,读取完A文件之后读取B文件,再读取C文件,代码如下
fs.readFile(fileA, (err, data)=> {
 fs.readFile(fileB, (err, data)=> {
 fs.readFile(fileC, (err,data)=>{
 //do something
 })
 });
});
可见,三个回调函数代码看来就够呛了,有时在实际业务中还不止嵌套这几个,难以管理。
这时候Promise出现了!它不是新的功能,而是一种新的写法,用来解决“回调地狱”的问题。
我们再假定一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果,用setTimeout()来模拟异步操作
/**
 * 传入参数 n,表示这个函数执行的时间(毫秒)
 * 执行的结果是 n + 200,这个值将用于下一步骤
 */
function A(n) {
 return new Promise(resolve=> {
 setTimeout(()=> resolve(n + 200), n);
 });
}
function step1(n) {
 console.log(`step1 with ${n}`);
 return A(n);
}
function step2(n) {
 console.log(`step2 with ${n}`);
 return A(n);
}
function step3(n) {
 console.log(`step3 with ${n}`);
 return A(n);
}
上面代码中有4个函数,A()返回一个Promise对象,接收参数n,n秒后执行resolve(n+200)。step1、 step2、step3对应三个步骤
现在用Promise实现这三个步骤:
function doIt() {
 console.time('do it now')
 const time1=300;
 step1(time1)
 .then( time2=>step2(time2))
 .then( time3=> step3(time3))
 .then( result=> {
 console.log(`result is ${result}`)
 });
}
doIt();
输出结果如下
step1 with 300
step2 with 500
step3 with 700
result is 900
result是step3()的参数700+200=900。
可见,Promise的写法只是回调函数的改进,用then()方法免去了嵌套,更为直观。
但这样写绝不是最好的,代码变得十分冗余,一堆的then。
所以,最优秀的解决方案是什么呢?
开头暴露了,就是async/await
讲async前我们先讲讲协程与Generator
三、协程
协程(coroutine),意思是多个线程相互协作,完成异步任务。
它的运行流程如下
协程A开始执行
协程A执行到一半,暂停执行,执行的权利转交给协程B。
一段时间后B交还执行权
协程A重得执行权,继续执行
上面的协程A就是一个异步任务,因为在执行过程中执行权被B抢了,被迫分成两步完成。
读取文件的协程代码如下:
function task() {
 // 其他代码
 var f=yield readFile('a.txt')
 // 其他代码
}
task()函数就是一个协程,函数内部有个新单词yield,yield中文意思为退让,
顾名思义,它表示执行到此处,task协程该交出它的执行权了。也可以把yield命令理解为异步两个阶段的分界线。
协程遇到yield命令就会暂停,把执行权交给其他协程,等到执行权返回继续往后执行。最大的优点就是代码写法和同步操作几乎没有差别,只是多了yield命令。
这也是异步编程追求的,让它更像同步编程
四、Generator函数
Generator是协程在ES6的实现,最大的特点就是可以交出函数的执行权,懂得退让。
function* gen(x) {
 var y=yield x +2;
 return y;
 }
 
 var g=gen(1);
 console.log( g.next()) // { value: 3, done: false }
 console.log( g.next()) // { value: undefined, done: true }
上面代码中,函数多了*号,用来表示这是一个Generator函数,和普通函数不一样,不同之处在于执行它不会返回结果,
返回的是指针对象g,这个指针g有个next方法,调用它会执行异步任务的第一步。
对象中有两个值,value和done,value 属性是 yield 语句后面表达式的值,表示当前阶段的值,done表示是否Generator函数是否执行完毕。
下面看看Generator函数如何执行一个真实的异步任务
var fetch=require('node-fetch');
function* gen(){
 var url='https://api.github.com/users/github';
 var result=yield fetch(url);
 console.log(result.bio);
}
var g=gen();
var result=g.next();
result.value.then( data=> return data.json)
 .then (data=> g.next(data))
上面代码中,首先执行Generator函数,得到对象g,调用next方法,此时
result={ value: Promise { <pending> }, done: false }
因为fetch返回的是一个Promise对象,(即value是一个Promise对象)所以要用then才能调用下一个next方法。
虽然Generator将异步操作表示得很简洁,但是管理麻烦,何时执行第一阶段,又何时执行第二阶段?
是的,这时候到Async/await出现了!
五、Async/await
从回调函数,到Promise对象,再到Generator函数,JavaScript异步编程解决方案历程可谓辛酸,终于到了Async/await。很多人认为它是异步操作的最终解决方案(谢天谢地,这下不用再学新的解决方案了吧)
其实async函数就是Generator函数的语法糖,例如下面两个代码:
var gen=function* (){
 var f1=yield readFile('./a.txt');
 var f2=yield readFile('./b.txt');
 console.log(f1.toString());
 console.log(f2.toString());
};
var asyncReadFile=async function (){
 var f1=await readFile('./a.txt');
 var f2=await readFile('./b.txt');
 console.log(f1.toString());
 console.log(f2.toString());
};
上面的为Generator函数读取两个文件,下面为async/await读取,比较可发现,两个函数其实是一样的,async不过是把Generator函数的*号换成async,yield换成await。
1.async函数用法
上面说了async不过是Generator函数的语法糖,那为什么要取这个名字呢?自然是有理由的。
async是“异步”,而await是async wait的简写,即异步等待。所以应该很好理解async用于声明一个function是异步的,await用于等待一个异步方法执行完成
下面来看一个例子理解async命令的作用
async function test() {
 return "async 有什么用?";
}
const result=test();
console.log(result) 
输出:
Promise { 'async 有什么用?' }
可以看到,输出的是一个Promise对象!
所以,async函数返回的是一个Promise对象,如果直接return 一个直接量,async会把这个直接量通过PromIse.resolve()封装成Promise对象
注意点
一般来说,都认为await是在等待一个async函数完成,确切的说等待的是一个表示式,这个表达式的计算结果是Promise对象或者是其他值(没有限定是什么)
即await后面不仅可以接Promise,还可以接普通函数或者直接量。
同时,我们可以把async理解为一个运算符,用于组成表达式,表达式的结果取决于它等到的东西
等到非Promise对象 表达式结果为它等到的东西
等到Promise对象 await就会阻塞后面的代码,等待Promise对象resolve,取得resolve的值,作为表达式的结果
还是那个业务,分多个步骤完成,每个步骤依赖于上一个步骤的结果,用setTimeout模拟异步操作。
/**
 * 传入参数 n,表示这个函数执行的时间(毫秒)
 * 执行的结果是 n + 200,这个值将用于下一步骤
 */
function takeLongTime(n) {
 return new Promise(resolve=> {
 setTimeout(()=> resolve(n + 200), n);
 });
}
function step1(n) {
 console.log(`step1 with ${n}`);
 return takeLongTime(n);
}
function step2(n) {
 console.log(`step2 with ${n}`);
 return takeLongTime(n);
}
function step3(n) {
 console.log(`step3 with ${n}`);
 return takeLongTime(n);
}
async实现方法
async function doIt() {
 console.time("doIt");
 const time1=300;
 const time2=await step1(time1);
 const time3=await step2(time2);
 const result=await step3(time3);
 console.log(`result is ${result}`);
 console.timeEnd("doIt");
}
doIt();
输出结果和上面用Promise实现是一样的,但这个代码结构看起来清晰得多,几乎跟同步写法一样。
2. async函数的优点
(1)内置执行器
Generator 函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器。也就是说,async 函数的执行,与普通函数一模一样,只要一行。
(2) 语义化更好
async 和 await,比起星号和 yield,语义更清楚了。async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
(3)更广的适用性
yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。

以上就是中大厂的面试知识点汇总,算不上包罗万象,但是涵盖的知识点还是比较齐全的,只要你能认真看完本文并理解了,那面试应该是没啥大问题的。当然,其中也少不了你自己的努力,还有更多的知识点需要你去学习。前端就是这样,招聘的是工程师,干活却是螺丝钉。这就要求各位前端coder们,不能只注重业务,平时也要给自己充电,知其然知其所以然,扩展自己的知识范围,懂得越多,在前端这条路上也才能走的更稳、更远。

最后,希望看过我文章的都找到好工作,也不枉我辛苦一场!!!

学习网页的概念和分类,了解静态网页和动态网页的不同;了解网页浏览器的工作原理。了解HTML,XHTML,HTML5的概念,制作简单的HTML页面的开发。

什么是网页

可以在internet上通过网页浏览信息,如新闻,图片等,还可发布信息,如招聘信息等,网页是在某个地方某一台计算机上的一个文件。

网页主要由3部分组成:结构,表现,行为。

静态网页的特点是不论在何时何地浏览这个网页,看到的形式和内容都相同,且只能浏览,用户无法与网站进行互动。静态页面由HTML编写,扩展名一般为.htm, .html, .shtml, .xml等。与动态页面相比,动态网页是以.asp, .jsp, .php, .perl, .cgi等形式为后缀。

动态网页指网页的内容可以根据某种条件而自动改变。

网页浏览器的工作原理

采用B/S结构,即浏览器/服务器结构,用户工作界面是通过www浏览器来实现的:

  1. 事务逻辑主要在服务器端实现,极少部分的事务逻辑在前端实现。
  2. 大大简化了客户端的计算机载荷。
  3. 减轻了系统维护与升级的成本和工作量。
  4. 降低了用户的总体成本。

浏览器的工作原理:

  1. 浏览器通过HTML表单或超链接请求指向一个应用程序的URL。
  2. 服务器收到用户的请求。
  3. 服务器执行已接收创建的指定应用程序。
  4. 应用程序通常基于用户输入的内容,执行所需要的操作。
  5. 应用程序把结果格式化为网络服务器和浏览器能够理解的文档,即通常所说的HTML网页。
  6. 网络服务器最后将结果返回到浏览器中。

www的基础是HTTP协议,web浏览器就是用于通过url来获取并显示web网页的一种软件工具,url用于指定要取得的Internet上资源的位置与方式。

HTML和HTML5

HTML是一种用来制作超文本文档的简单标记语言,用其编写的超文本文档称为HTML文档,它能独立于各种操作系统平台。

可扩展超文本标记语言XHTML:

XHTML是不需要编译,可以直接由浏览器执行,是一种增强了的HTML。它的可扩展性和灵活性将适应未来网络应用的更多需求,是基于XML的应用。开发者在HTML4.0的基础上,用XML的规则对其进行一些扩展,由此得到了XHTML,所以,建立XHTML的目的是为了实现HTML向xml的过渡。

HTML5简化了:<!DOCTYPE html>,简化了DOCTYPE,简化了字符集声明,以浏览器的原生能力替代脚本代码的实现,简单而强大的HTML5API。

HTML网页的结构

文件扩展名是操作系统用来标志文件格式的一种机制。扩展名如同文件的身份说明,区别了文件的类别和作用。

HTML网页的文件后缀名是.html或者.htm.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"xxx">
声明的作用,告诉浏览器所书写的HTML代码的版本。
复制代码

<meta>标签,是HTML文档<head>标签内的一个辅助性标签,meta标签分为2个重要的属性:name和http-equiv,通常用于能够优化页面被搜索的可能性。

meta标签下name属性的使用:

<head>
 <meta name="keywords" content="nine, twenty-three">
 <meta name="description" content="...">
 <meta name="generator" content="Dreamweaver">
 <meta name="author" content="depp">
 <meta name="robots" content="all">
</head>
复制代码
  1. keywords向搜索引擎说明页面的关键字,在content后输入供搜索的具体关键字。
  2. description向搜索引擎描述页面的主要内容。
  3. generator向页面描述生成的软件名,在content后面输入具体的软件名称。
  4. author网页的设计者,在content后面输入设计者的具体姓名。
  5. robots限制搜索的方式,在content后面通常可输入all,one,index,noindex,follow,nofollow其中之一,不同的属性分别有不同的作用,限制页面被搜索的方式。

meta标签下的另一个属性http-equiv,其作用是反馈给浏览器一些明确的信息,帮助浏览器更精确地展示页面。

<head>
 <meta http-equiv="content-type"  content="text/html; charset=gb2312"/>
</head>
复制代码
  1. refresh 对属性的具体描述,说明是令页面自动跳转的效果。
  2. content 后跟等待的时间,url后跟跳转的页面链接地址。

link标签,定义了一个外部文件的链接,经常被用于链接外部css样式。

base标签为整个页面定义了所有链接的基础定位,其主要的作用是确保文档中所有的相对url都可以被分解成确定的文档地址。

style标签用于定义css的样式。表明了在页面中引入一个.style的样式表。

script标签用于定义页面内的脚本。

titl标题标签,body体标签.

一个好的HTML文档应具备以下3个方面:

  1. 代码使用标准规范,不应该有错误的拼写
  2. 代码结构清晰,使人一目了然
  3. 没有错误或者多余不必要的代码出现

文本设计

<br>..</br>
<p>...</p>
复制代码
<p align=left>...</p>
<p align=center>...</p>
<p align=right>...</p>
复制代码

给文本加标注:<acronym title="">...</acronym>注释的内容放在title属性后的引号中,被注释的内容放在标签内。

无序列表:ul,li,有序列表:ol li

定义列表:

<dl>
 <dt>...</dt>
 <dd>...</dd>
 <dt>...</dt>
 <dd>...</dd>
</dl>
复制代码

网页中的图像设计

  1. jepg格式的图像,该文件是常见的图像格式,.jpg后缀名,jpeg文件是经过压缩的一种图像。压缩的图像可以保持为8位,24位,32位深度的图像,压缩比率可以高达100:1.jpeg可以很好地处理大面积色调的图像。
  2. png格式的图像,后缀名.png,这是一种能存储32位信息的位图图像,采用的是一种无损压缩的方式。支持透明信息,指图像以浮现在其他页面文件或页面图像之上。
  3. gif格式的图像,是一种图像交互格式,后缀名.gif,只支持256色以内的图像,gif文件的图像效果是很差的。

所以总的来说:jepg可以压缩图像的容量,png的质量较好,gif可以做动画。

矢量图

说说矢量图和位图最大的区别:

无论是否对图像进行缩放,都不会影响矢量图的效果,但会影响图的质量。

设计者一般只愿意将logo,ui图标,标识符号等简单图像存为矢量图。

图像的分辨率

分辨率的单位是dpi即每英寸显示的线数。通常所指的分辨率有两种,屏幕分辨率和图片分辨率,屏幕分辨率即计算机显示器默认的分辨率。

一般目前大部分显示器的分辨率是1024px x 768px,图片分辨率定义是用于量度位图图像内数据量多少的一个参数。

分辨率越高的图像,包含的数据越多,图像的容量就越大,会消耗更多的计算机资源,需要更大的存储空间。

分辨率指的是每英寸的像素值,通过像素和分辨率的换算可以测算图片的长度。

页面中的图像

<img src=... alt=.../>
复制代码
  1. 使图像的顶部和同一行的文本对齐
<img style="vertial-align:text-top"/>
复制代码
  1. 使图像的中部和同一行的文本对齐
<img style="vertical-align:middle"/>
复制代码
  1. 使图像的底部和同一行的文本对齐
<img style="vertical-align:text-bottom"/>
复制代码
  1. 使图像的底部和文本的基线对齐
<img style="vertical-alignbaseline"/>
复制代码

hspace=30px表示图像左,右两边与页面其他内容隔30px的距离。vspace=30px表示图像上,下两边与页面的其他内容的间隔距离是30px。

<img src="" widht="" height="">

<img src="..." border=>

<hr align=".." width="..." size="...">

<a href="链接对象的路径">链接锚点对象</a>
复制代码

把邮箱留给需要联系你的人

<a href="mailto:邮箱地址">链接锚点对象</a>
复制代码
  1. 链接还未被访问:a:link{...}
  2. 链接被选中:a:active{...}
  3. 光标滑过链接:a:hover{...}
  4. 链接被访问后:a:visited{...}
dashed 虚线

double 双线

groove 槽线

inset 内陷

outset 外陷
复制代码

热点图像区域的链接

map标签:

<map id=...>
 <area shape="..." coords="..." href="...">
</map>
复制代码

shape属性,用于确定选区的形状,rect矩形,circle圆形,poly多边形。href属性,就是超链接。coords属性,用于控制形状的位置,通过坐标来找到这个位置。

网页中的表单

计算矩形的面积

<html>
<head>
<title>计算矩形的面积</title>
<style type="text/css">
 .result {font-weight:bold;}
</style>
<script language="JavaScript">
function calculate() {
 var length=document.data.length.value;
 var width=document.data.width.value;
 var height=document.data.height.value;
 var area=document.getElementById('area');
 area.innerHTML=length*widht;
 volume.innerHTML=length*widht*height;
 }
</script>
复制代码

创建表单

  1. action属性,通过form标签定义的表单里必须有action属性才能将表单中的数据提交出去:
<form action="my.php"></form>
复制代码

它表明了这是一个表单,其作用是提交my.php页面中的数据。

  1. method属性告诉浏览器数据是以何种方式提交出去的。method属性下可以有2个选择:post或者get。
  2. name属性,为了令递交出去的表单数据能够被处理这些数据的程序识别。
<form name="data">
复制代码
  1. 编码方式,enctype代表HTML表单数据的编码方式。

表单的工作原理

原理:在客户端接收用户的信息,然后将数据递交给后台的程序来操控这些数据。

<script language="JavaScript">
复制代码

如果通过引用外部javascript程序,就像链接外联样式:

<script type="text/javascript" src="dada.js"></script>
复制代码

创建表单

  1. action属性,有action属性才能将表单中的数据提交出去:
<form action="da.php"></form>
复制代码
  1. method 属性,作用是告诉浏览器数据是以何种方式提交出去的。在method属性下可以有2个选择,post或get。

提交方式用get,表单域中输入的内容会添加在action指定的url中,当表单提交之后,用户会获取一个明确的url。get在安全性上较差,所有表单域的值直接呈现。post除了有可见的处理脚本程序,别的东西都可以隐藏。

  1. name属性,添加name属性是为了令递交出去的表单数据能够被处理这些数据的程序识别。
<form name="dada">
复制代码
  1. 编码方式:enctype代表HTML表单数据的编码方式,application/x-www-form-urlencoded, multipart/form-data, text/plain三种方式。
  • application/x-www-form-urlencoded是标准的编码方式,提交的数据被编码为名称/值对。
  • multipart/form-data属性表示数据编码为一条消息,为表单定义mime编码方式,创建了一个与传统不同的post缓冲区,,页面上每个控件对应消息中的一个部分。
  • text/plain表示数据以纯文本的形式进行编码,这样在信息中将不包含控件或者格式字符。
  • multipart/form-data方式上传文件时,不能使用post属性。
  1. 目标显示方式,表示在何处打开目标url,可以设置4种方式。
  • _blank表示在新的页面中打开链接
  • _self表示在相同的窗口中打开页面
  • _parent表示在父级窗口中打开页面
  • _top表示将页面载入到包含该链接的窗口,取代任何当前在窗口中的页面。
<form action="mailto:da@qq.com" method="post" name="dada"
enctype="text/plain" target="_blank"></form>
复制代码

表单域

是指用户输入数据的地方,表单域可分为3个对象,input, textarea, select。

input对象下的多种表单的表现形式。

<input name="" type="" value="" size="" maxlength="">
复制代码
  • type表示所定义的是哪种类型的表单形式
  • size表示文本框字段的长度
  • maxlength表示可输入的最长的字符数量
  • value表示预先设置好的信息
  1. text单行的文本框
  2. password将文本替换*的文本框
  3. checkbox只能做二选一的是或否选择
  4. radio从多个选项中确定的一个文本框
  5. submit确定命令文本框
  6. hidden设定不可浏览用户修改的数据
  7. image用图片表示的确定符号
  8. file设置文件上传
  9. button用来配合客户端脚本
<form action="" method="post">
<input name="name" type="text" size="20" maxlength="12">
</form>
<input name="secret" type="password" size="20" maxlength="20">

<input name="one" type="radio" value="one" checked="checked">
<input name="one" type="radio" value="two">

<input type="submit" value="确定">
<input type="reset" value="恢复">
复制代码

创建submit按钮或reset按钮时,name属性不是必需的。

hidden隐藏域的样式表单

使用hidden来记录页面的数据并将它隐藏起来,用户对这些数据通常并不关心,但是必须提交数据。

<form action=da.asp>
<input type=hidden name=somehidden value=dada>
<input type=submit value=下一页>
</form>
复制代码

image样式的表单

<input type="image" src="图片/小图标.jpg" alt="确定">
复制代码
  • src属性指定这张图像的路径
  • alt属性添加文本注释

file上传文件的样式表单

file样式表单允许用户上传自己的文件

<html>
<head>
<title>file样式的表单</title>
<style type="text/css">
body {font:120% 微软雅黑;}
input {font:100% 微软雅黑;}
</style>
</head>
上传我的文件:
<form action="..." method="post" enctype="multipart/form-data">
<input type="file" name="uploadfile" id="uploadfile"/>
</form>
</body>
</html>
复制代码

textarea对象的表单

textarea对象的表单

<html>
<head>
<title>file样式的表单</title>
<style type="text/css">
body{font:120% 微软雅黑;}
textarea{font:80% 微软雅黑;color:navy;}
</style>
</head>
<body>
留言板
<form action="..." method="post" enctype="multipart/form-data">
<textarea name="dada" rows="10" cols="50" value="dada">请说:</textarea>
</form>
</body>
</html>
复制代码

select对象的表单

select对象的表单

<form action="">
 地址:
 <select name="da1">
  <option>1</option>
 </select>
</form>
复制代码

使用optgroup标签配合label属性来给选项分类:

<select name="上海">
<optgroup label="da1">
<option>1</option>
</optgroup>
<optgroup label="da2">
<option>2</option>
</optgroup>
</select>
复制代码

在select标签中加入size属性即可,如size=6表示是一个能容纳6行文字的文本框,超出设置的行数时,将出现滚动条。

<select name="上海" size="6">
复制代码

表单域集合:表单域的代码由fieldset标签和legend标签组合而成。

<form action="..." method="post">
<fieldset>
<legend>注册信息:</legend>
输入用户名:<input name="name" type="text" size="20" maxlength="12">
</fieldset>
</form>
复制代码

表单输入类型

  • url类型的input元素是专门为输入url地址定义的文本框。
<input type="url" name="webUrl" id="webUrl" value="http://wwwxxx"/>
复制代码
  • email类型的input元素是专门为输入email地址定义的文本框。
<input type="email" name="dada" id="dada" value="23@qq.com"/>
复制代码
  • range类型的input元素用于把输入框显示为滑动条,可以作为某一特定范围内的数值选择器。
<input type="range" name="volume" id="volume" min="0" max="1" step="0.2"/>
复制代码
  • number类型的Input元素是专门为输入特定的数字而定义的文本框。
<input type="number" name="score" id="score" min="0" max="10" step="0.5"/>
复制代码
  • tel类型的input元素是专门为输入电话号码而定义的文本框,没有特殊的验证规则。
  • search类型的input元素是专门为输入搜索引擎关键词定义的文本框,没有特殊的验证规则。
  • color类型的input元素默认会提供一个颜色选择器。
  • date类型的Input元素是专门用于输入日期的文本框,默认为带日期选择器的输入框。
  • month提供一个月的选择器,week提供一个周选择器,time会提供时间选择器,datetime会提供完整的日期和时间选择器,datetime-local会提供完整的日期和时间选择器。

增加表单的特性以及元素

  1. form特性:
<input name="name" type="text" form="form1" required/>
<form id="form1">
<input type="submit" value="提交"/>
</form>
复制代码
  1. formaction特性,将表单提交至不同的页面。
<form id="form1" method="post">
<input name="name" type="text" form="form1"/>
<input type="submit" value="提交到page1" formaction="?page=1”/>
<input type="submit" value="提交到page2" formaction="?page=2"/>
<input type="submit" value="提交"/>
</form>
复制代码
  • formmethod特性可覆盖表单的method特性
  • formenctype特性可覆盖表单的enctype特性
  • formnovalidate特性可覆盖表单的novalidate特性
  • formtarget特性可覆盖表单的target特性

placeholder特性

<input name="name" type="text" placeholder="请输入关键词"/>
复制代码

autofocus特性:用于当页面加载完成时,可自动获取焦点,每个页面只允许出现一个有autofocus特性的input元素。

<input name="key" type="text" autofocus/>
复制代码

autocomplete特性用于form元素和输入型的Input元素,用于表单的自动完成。

input name="key" type="text" autocommplete="on"/>
复制代码

autocomplete特性有三个值,可以指定"on","off"和""不指定,不指定就将使用浏览器的默认设置。

<input name="email" type="email" list="emaillist"/>
<datalist id="emaillist">
<option value="23#qq.com">xxxx</option>
</datalist>
复制代码

keygen元素提供一个安全的方式来验证用户。

<form action="">
<input type="text" name="name"/><br>
<keygen name="security"/>
<br><input type="submit"/>
</form>
复制代码
  1. keygen元素有密钥生成的功能,在提交表单时,会分别生成一个私人密钥和一个公共密钥。
  2. 私人密钥保存在客户端,公共密钥则通过网络传输至服务器。

output元素

  1. output元素用于不同类型的输出,比如计算结果或脚本的输出等。
  2. output元素必须从属于某个表单,即写在表单的内部。
<form oninput="x.value=dada.value">
<input type="range" name="volume" value="50"/>
<output name="x"></output>
</form>
复制代码

required

为某个表单内部的元素设置了required特性,那么这项的值不能为空,否则无法提交表单。

<input name="name" type="text" placeholder="dada" required/>
复制代码

pattern

  1. pattern用于为Input元素定义一个验证模式。
  2. 该特性值是一个正则表达式,提交时会检查输入的内容是否符合给定的格式,如果不符合则不能提交。
<input name="code" type="text" value="" pattern="[0-9]{6}" placeholder="da"/>
复制代码

min,max,step

  1. min表示允许范围内的最小值
  2. max表示允许范围内的最大值
  3. step表示合法数据的间隔步长
<input type="range" name="dada" id="dada" min="0" max="1" step="0.2"/>
复制代码

novalidate

  1. 用于指定表单或表单内在提交时不验证
  2. 如果在form元素应用novalidate特性,则表单中的所有元素在提交时都不需要再验证
<form action="dada.asp" novalidate="novalidate">
<input type="email" name="user_email"/>
<input type="submit"/>
</form>
复制代码

validity

  1. 获取表单元素的ValidityState对象,该对象包含8个方面的验证结果
  2. ValidityState对象会持续存在,每次获取validity属性时,返回的是同一个ValidityState对象
var validityState=document.getElementById("username").validity;
复制代码

willValidate属性

  1. 用于获取一个布尔值,表示表单元素是否需要验证
  2. 如表单元素设置了required特性或pattern特性,则willValidate属性的值为true,即表单的验证将执行
var willValidate=document.getElementById("username").willValidate;
复制代码

validationMessage

  1. 获取当前表单元素的错误提示信息。
var validationMessage=document.getElementById("username").validationMessage;
复制代码

点关注,不迷路

好了各位,以上就是这篇文章的全部内容,能看到这里的人都是人才。我后面会不断更新技术相关的文章,如果觉得文章对你有用,欢迎给个“赞”,也欢迎分享,感谢大家 !!

TML 5对表单新增了很多功能和属性,可以更加方便地进行表单开发,form属性代码如下:

所以在HTML 5中定义了表单的从属关系,而不再完全依赖form的位置。在下面的代码中,输入框txtPhone是属于表单myForm的,因此可以提交输入框内容。在之前的HTML中这种写法是不能提交txtPhone输入框的内容的。 placeholder属性一般用于文本输入框上,其主要作用是当文本框处于未输入的状态并且内容为空时,显示一段提示文本内容。

<input type="text" id="txtUserName" class="form-control" placeholder="请输入用户名"/>

这个属性达到的效果是我们常见的水印效果,如图所示。

autofocus属性的作用是指定控件自动活动的焦点,一个页面中只能有一个控件具有该属性。

HTML 5允许单行文本框中使用list属性,配合datalist元素一起使用。list主要用于提示文本框输入,datalist用于提供数据源,目前支持该特性的浏览器较少。

Autocomplete属性用于完成自动输入的功能,有两个值;on和off,分别代表自动完成输入和禁止自动完成输入。很多浏览器不支持该属性,但是自动完成插件是笔者平时使用较多的。

Required属性是用作必填属性,如果使用到了这个属性则当表单中的元素为空时无法提交,此属性作用于输入框元素上。