Doctype的作用,标准模式和混杂模式有什么区别
html语义化的理解
html5的离线存储怎么使用,工作原理
在用户和因特网没有连接时,可以正常访问站点和应用,在用户和因特网链接的时候可以更新用户机器上的缓存文件
原理: html5是一种基于新建一个appcache的文件的缓存机制,通过这个文件上的解析清单离线存储资源,这些资源就会响cookie一样被存储下来之后当网络处于离线状态下,浏览器会通过离线存储的数据进行页面展示
使用:
iframe有那些缺点?
laber的作用是什么?要怎么用
点击这里和点击输入框一样
laber>
<laber>data:laber>
对页面元素进行编辑
实现不用border,实现1px高的线
<div style="height:1px;overflow:hidden;background:red"></div>
行内元素和块级元素,行内元素不会换新航,块级元素会格式化为块状,会换行,行内元素不呢能设置宽度和高度,熟悉的行内元素有span,i,em等,img是行内元素,但是可以设置宽度和高度。主要原因是置换元素和非置换元素。
置换元素和非置换元素不仅行内元素有区分,块级元素也有区分,比如iframe以及个别时候的audio和canvas也是置换元素。
置换元素是根据标签的属性来决定元素显示的具体内容,比如img标签就是根据src属性来显示,input标签是根据type属性来显示数据框,这些元素往往没有实际内容,也就是一个空元素。但是大多数元素都是不可替换元素,比如div p,他们都把实际的内容展示出来。
可置换元素有img|input|select|textarea|button。他们区别于一般的inline元素,这些元素拥有内在尺寸,可以设置高度和宽度,他们的性质和设置了inline-block的属性一样,
行内置换元素设置上下padding,可以撑大父元素,而行内非置换元素设置上下padding只是范围扩大,不会影响父元素。
语义化的标签基本都是h5的,比如header footer nav article
li标签之前看不见的空白间隔是什么原因引起的,有什么解决办法
行框的排列会受到中间空白(回车换行的影响)因为空格也属于字符,这些空白也会被应用样式,占据空间,把字符大小设置为0或者负边距,或者删除空白就行。
w3c标准中,块元素的总宽度就是content,而ie标准盒模型中块元素的总宽度就是content+2 * padding+2 * border。导致他们采用那个标准,是html文件顶部的doctype
行内元素有 br input span b i
BFC是块级格式化上下文,是css2.1的规范,决定了元素如何对其内容进行定位,以及与其他元素的关系和作用。。BFC提供了一个环境,html元素在这个环境中按照固定的规则进行布局,一个环境中的元素不会影响到其它环境的布局。浮动元素内部子元素主要受该浮动元素影响。
触发BFC
css盒子模型中的padding是透明的,可以显示背景
canvas和svg的区别
垂直居中的方法
flex
.flex {
display : flex;
align-items : center;
align-items : center;
}
单行文字垂直居中,只需要height和line-height一样高
多对象的垂直居中技巧,将多个元素用一个大的div包裹起来,并且设置display是inline-block设置高度。
absolute + margin负值
absolute+ translate
flex+margin
import和link的区别
position定位
display
双飞翼和圣杯布局
圣杯布局和双飞翼布局基本上是一致的,都是两边固定宽度,中间自适应的三栏布局,其中,中间栏放到文档流前面,保证先行渲染。解决方案大体相同,都是三栏全部float:left浮动,区别在于解决中间栏div的内容不被遮挡上,圣杯布局是中间栏在添加相对定位,并配合left和right属性,效果上表现为三栏是单独分开的(如果可以看到空隙的话),而双飞翼布局是在中间栏的div中嵌套一个div,内容写在嵌套的div里,然后对嵌套的div设置margin-left和margin-right,效果上表现为左右两栏在中间栏的上面,中间栏还是100%宽度,只不过中间栏的内容通过margin的值显示在中间。
圣杯
DOM:
<body>
<div id="hd">headerdiv>
<div id="bd">
<div id="middle">middlediv>
<div id="left">leftdiv>
<div id="right">rightdiv>
div>
<div id="footer">footerdiv>
body>
<style>
#hd{
height:50px;
background: #666;
text-align: center;
}
#bd{
/*左右栏通过添加负的margin放到正确的位置了,此段代码是为了摆正中间栏的位置*/
padding:0 200px 0 180px;
height:100px;
}
#middle{
float:left;
width:100%;/*左栏上去到第一行*/
height:100px;
background:blue;
}
#left{
float:left;
width:180px;
height:100px;
margin-left:-100%;
background:#0c9;
/*中间栏的位置摆正之后,左栏的位置也相应右移,通过相对定位的left恢复到正确位置*/
position:relative;
left:-180px;
}
#right{
float:left;
width:200px;
height:100px;
margin-left:-200px;
background:#0c9;
/*中间栏的位置摆正之后,右栏的位置也相应左移,通过相对定位的right恢复到正确位置*/
position:relative;
right:-200px;
}
#footer{
height:50px;
background: #666;
text-align: center;
}
style>
行内元素是否可以设置margin和padding
看html8 置换元素和非置换元素的区别
清除浮动的几种方式。
父级元素设置伪类
.clearfloat{zoom:1}
.clearfloat:after {
content : '';
display:block;
clear:both;
visibility:hidden;
}
/*
原理:利用css提高的clear:both清除浮动,让父级div能自动获取到高度
优点:浏览器支持比较好,不容易出现兼容性问题
*/
在底部添加一个空div,添加属性
.newDiv {
clear:both;
}
/*
原理:添加一个空div,利用css提高的clear:both清除浮动,让父级div能自动获取到高度
缺点:添加了一个div,增加了dom节点
*/
父级div设置高度
/*
缺点明显,只适合固定高度的div
*/
父级div设置overflow:hideen
/*
必须定义width或zoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度
不能使用position
*/
父级元素设置float
/*
形成了bfc,浏览器会检测高度
*/
媒体查询
@media screen and (min-width:1200px)
@media screen and (min-width:992px)
@media screen and (min-width:768px)
@media screen and (min-width:480px)
移动端开发过程中,因为手机的dpr(设备像素比不同),需要根据dpr来修改图标的大小,判断使用@2x 图 还是 @3x 图,解决高清的适配。
/*less,sass这类css预处理语言中的混合,可以理解成自定义了一段代码,后面可以用@include调用*/
@mixin bg-image($url) {
background-image: url($url + "@2x.png");
@media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3){
background-image: url($url + "@3x.png");
}
}
/*用@include调用*/
div{
width:30px;
height:20px;
background-size:30px 20px;
background-repeat:no-repeat;
@include bg-image('../../../../static/image/map_loading');
}
//scss
@mixin box-size($width:100px,$height:100px) {
width: $width;
height: $height;
}
.demo{
@include box-size;
}
.demo2{
@include box-size(200px,300px);
}
0.5px实现的几种方式
利用渐变来做
.bd-t {
position:relative;
}
.bd-t :after {
content : '';
position : absolute;
top:0;
left:0;
width:100%;
height:1px;
background-image: linear-gradient(0deg, transparent 50%, #e0e0e0 50%);
}
/*
为了实现盒子顶部边框0.5px的伪代码:border-top:0.5px solid #e0e0e0; 的效果,使用after,作为一个钩子,宽度100%,高度1px,背景渐变,一半透明,一半有颜色,这么干是可以的。
*/
使用缩放
.bd-t {
position :relative;
}
.bt-d:after {
content:'';
position ;absolute;
left:0;
top:0;
width:100%;
height:1px;
transform:scaleY(0.5);
background:black;
/*或者
border-top 1px solid black;
*/
}
使用缩放解决四边都是0.5
.bd-t {
position:relative;
}
.bd-t:after {
content:"";
position:absolute;
z-index:-1;
width:200%;
height:200%;
transform:sacle(0.5,0.5);
border:1px solid black;
}
使用background-img
.bd-t {
position:relative;
}
.bd-t:after {
content : '';
position: position;
left:0;
top:0;
width:100%;
border-top:1px solid transparent;
border-image: url('pic.png') 2 1 1 1 stretch;
}
使用同周边相似的浅色,利用视觉效果,让用户产生错觉。
在浏览器中我们可以开启硬件加速,使得gpu发挥作用。cssanimations,transform,transitions不会自动开启gpu加速,而是由浏览器的缓慢的软件渲染引擎来执行。现代浏览器检测到页面中某个dom元素应用了某些css规则的时候就会开启,显著的是元素的3d变换,我们可以欺骗浏览器开启硬件加速。
transform:translateZ(0);
jquery和css3做动画的区别
$("p").animate({"bottom":p*9},3000,function(){
// 回调函数
$("p").animate({"bottom":-p},6000);
//css3
@keyframes myfirst
{
from {background: red;}
to {background: yellow;}
}
div
{
animation: myfirst 5s;
-moz-animation: myfirst 5s; /* Firefox */
-webkit-animation: myfirst 5s; /* Safari 和 Chrome */
-o-animation: myfirst 5s; /* Opera */
}
不可以继承的, display,margin,padding,border,backgroud,height,width,position等
css多列等高是如何实现的。
利用padding-bottom(+)和marin-bottom(-)正负相抵。设置父容器overflow:hidden,这样父容器的高度就是它里面子元素没有设定padding-boddom的高度,当里面的任何一列高度增加了,那么父容器的高度就被撑到里面最高的那列的高度了。 其它的比这列矮的列会用他们的padding-bottom补偿这份高度差
全屏滚动的原理
比如要显示五个页面,可以设置高度为500%; 然后只显示100%;通过transform来使用
响应式布局就是一个网站可以兼容多个终端,而不是为每一个终端写一个版本,有点事面对不同分辨率设备灵活性强。但是他会工作量大,而且效率有点低,代码累赘,加载时间长。可以通过媒体查询来做
@media 设备名 only(选取条件) not(选取条件) and(选取条件)
视觉感动就是网页向下滑动的时候,控制背景的移动速度比前景移动速度慢来创建出令人惊叹的3d效果。可以用css实现
::before 和 :after中双冒号和单冒号 有什么区别?解释一下这2个伪元素的作用。
单冒号是用于css伪类,双冒号是css微元素, ::befare就是一个子元素的存在,定义在元素主体内容之前的一个微元素,并不存在dom中, after生成的会比before的靠后。
修改chrome记住密码之后自动填充表单的黄色背景,第一种情况是针对文本框是纯色背景的
input:-webkit-autofill, textarea:-webkit-autofill, select: -webkit-autofill {
background-color:rgb(250, 255, 189);
background-image :none,
color:rgb(0,0,0);
}
/*
设置背景色为白色
*/
还有一种情况是,input使用背景图片,图片不复杂的情况下可以使用第一种情况解决,纯色内阴影覆盖,
line-height
行高是只一行文字的高度,具体说的是两行文字极限之间的距离,css起高度作用的主要是height和line-height,一个没有定义height属性,最终表现一定是line-height。单行文本垂直居中只需要吧line-height设置为何height一样高。多行文本垂直居中需要设置display为inline-block
设置元素浮动之后,他的display的值会自动变成block,ie出现双边框设置inline就可以解决bug
position:fixed在安卓中无效怎么办。
fixed的元素是相对整个页面固定位置的,你在屏幕上滑动只是移动站合格所以的viewport,但是原来的网页还好好的在哪里,fixed的内容也没有变化位置,。需要在head中加入代码
<meta name="viewport" content="width=device-width, initial-scale=1.0,
maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
如果要手写动画,最小的时间间隔。
因为大多数显示器的默认分辨率是60hz,也就是1s刷新60次,所以莅临赏最小的时间间隔是1/60*1000 也就是16.7ms
有一个高度自适应的div,里面有两个div,一个高度是100px;希望另一个填满剩下的高度,
.con {
height: auto;
}
.top {
width:100%;
height:100px;
backgroun:red;
}
.bottom {
position: absolute;
top:100px;
width:100%;
bottom:0;
left:0;
right:0;
}
png, jpg, gif
png是无损的,压缩比高,色彩好,透明
jpg是针对相片的失真压缩,会皮怀的,
gif是一种位图格式,可以有动画
cookie隔离,看下面的cookie优化
移动端最小触控区域时44px*44px
css强制不换行,超出部分用省略号
{
white-space: nowrap; //文本强制不换行;
text-overflow:ellipsis; //文本溢出显示省略号;
overflow:hidden; //溢出的部分隐藏;
}
颜色渐变
background: linear-gradient(to right, dodgerBlue, skyBlue);
-webkit-background-clip: text;
rem实现页面兼容
例如:设计稿宽度是750px,有一个元素设计稿上的宽度是50px,设备物理宽度是375px,那么我们在页面上应该设置宽度为 width:50rem,相当于宽度是:50*(375/750)=25px;这里能正确算出在375px的设备上刚好占一半,其实可以想象为 rem=(375/750)。
2.一般浏览器的最小字体是12px,如果html的font-size=(375/750)px,相当于font-size=0.5px,那么这个数值就小于12px,会造成一些计算的错误,和一些奇怪的问题,*100后,font-size是50px,就可以解决这种字体小于12px的问题。
在header中写标签设置font-size的大小。
<script type="text/javascript">
document.documentElement.style.fontSize = document.documentElement.clientWidth / 750*100 + 'px';
</script>
移动端ios开发和andriod的区别
物理返回andriond会刷新,ios不会刷新
ios和安卓对json对象遍历的顺序相反
ios弹出键盘的时候,viewport的高度并不会边,但是安卓变,所以iosfixed在底部的元素显示不出来。
ios自带的浏览器是有双击缩放功能的。比如用户在ios里面点击了一个连接,由于用户可以进行双击缩放和双击滚动的操作,浏览器并不能确定用户是要打开这个链接还是要放大,所以需要等待三百ms来判断用户是判断用户是否再次点击。 所以就有了300ms延迟
解决方法有
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
移动端事件触发的顺序是,touchstart-》touchmove-》touchend-》click,所以fastclick的原理就是检测到touch事件的时候,通过dom自定义事件立即模拟click事件,同时把300ms之后的事件阻止掉
与之相关的还有点击穿透事件,比如页面有两个元素a和b,b元素在a元素的上面,我们在b元素的touchstart事件上注册了一个回调函数,这个回调函数的作用是隐藏b元素,我们发现,当点击b元素的时候,b被隐藏了,同时a元素触发了click事件。这是因为事件的处理顺序,click有300ms的延迟,touchstart是立即发生的,然后300ms之后,浏览器触发了click事件,但是这时候b已经没了,那就触发了a事件,同样用fastclick解决
移动端为什么用zepto而不是jquery
cookie,sessionStorage,localStorage的区别
获取鼠标点击的位置
判断一个对象是不是数组
ajax请求数据的流程
浏览器事件
事件就是文档或者浏览器窗口中发生的一些特定的交互瞬间,可以用监听器来监听事件。部分不支持冒泡的事件有
事件冒泡会从当前触发的目标事件一级一级向上传递,依次触发,知道document为止,事件捕获会从document开始触发,一级一级向下传递,依次触发,直到真正到目标为止
我们给一个dom同时绑定两个点击事件,一个用捕获,一个用冒泡。会执行几次事件,会先执行冒泡还是捕获?
会执行两次,先捕获,后冒泡
事件触发的顺序是事件捕获-> 事件触发 -> 事件冒泡
js基本数据类型有 null,undefined,string number boolean symbol
复杂数据类型 array object function
延迟js的运行,需要加上在script中加上defer属性
日期类转换到原始值能使用什么方法,toString
typeof Date.now() 的返回值是number
oxff^33 是异或的意思。
client是content+ 2*padding。 offset是content+ 2 * padding + 2 * border
scrollheight是真实的高度,自身高度加上滑动高度
[] == 0; [1]==1; [0] == 0
a标签不跳转有三种方式,第一种src=#,第二种 onclick函数return false,第三种href= javascript:void(0)
parseInt(string,radix)有两个参数,第一个参数是要解析的字符串,第二个参数是要解析的基数, 这个值在2-36之间, 省略的话会当做10来处理,小于2或者大于36会NaN
javascript有许多保留字不嫩用作标识符,比如arguments、break、case、catch、class、const、continue、debugger、default、delete、do、else、enum、eval、export、extends、false、finally、for、function、if、implements、import、in、instanceof、interface、let、new、null、package、private、protected、public、return、static、super、switch、this、throw、true、try、typeof、var、void、while、with、yield
事件循环队列的只是,是主线任务完成后,会完成所有微队列内的异步任务(promise),再去处理宏队列的任务,settimeout
每个对象都会在其内部初始化一个属性也就是prototype,当我们范文正对对象属性时,如果这个对象内部不存在这个属性,那么它就会去prototype中去找这个属性,这个prototype也会有自己的prototype。于是这样一直找下去,就是我们说的原型链的概念, instance.constructot.prototype = instance.proto
window对象是指浏览器打开的窗口,document对象时document对象的一个制度引用,是window对象的一个属性
全局函数无法查看局部函数,但是局部函数可以查看全局函数,当需要从局部函数查找某一属性和方法的时候,如果当前作用域没有找到,就会上诉到上层作用域查找,直到全局函数,这就是作用域链
上下文是基于对象的,上下文总是关键字this的值,this总是指向函数的直接调用者,当函数作为对象的方法被调用,this指向调用方法的对象 、 如果有new创建一个对象的实例的时候,那么this就指向new出来的这个对象,当调用一个未绑定函数,this默认指向全局上下文或者浏览器的window对象,如果在严格模式下,this指向undefined,当对象调用属性的时候,this指向调用的对象。call,bind,apply可以改变this的指向
当函数执行的时候,会创建一个称为执行上下文的内部对象,不是25的上下文,一个执行上下文就定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用同一个函数会导致创建多个执行上下文, 当js代码被浏览器载入后,默认最先进入的是一个全局的执行上下文,当在全局上下文中调用一个执行函数的时候,程序流就进入了该调用函数内,此时,引擎就会为该函数新建一个执行上下文,并且将其压入执行栈顶部,(作用域链)浏览器总是执行位于执行栈顶部的执行上下文,一旦执行完毕,该执行上下文就会从执行栈顶部弹出,并且控制权进入下一个执行上下文,这样子,执行栈中的指向上下文就会被一次执行并且弹出, 直到回到全局的执行上下文。
作用域链其实就是我们访问对象的属性和方法,当找不到的时候,就会通过scope,进行查找,scope连存储的执行上下文的集合,这个集合呈现链式连接,我们称之为作用域链
原型链就是我找一个属性首先会在f.proto中找,如果找不到,就去f.protot.proto中去找,直到找到null位置,这个串起来的链就是原型链
什么是闭包,为什么要用
闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。
javaScript中hasOwnProperty函数方法是返回一个布尔值,指出一个对象是否具有指定名称的属性。此方法无法检查该对象的原型链中是否具有该属性;该属性必须是对象本身的一个成员。
使用方法:
object.hasOwnProperty(proName)
其中参数object是必选项。一个对象的实例。
proName是必选项。一个属性名称的字符串值。
如果 object 具有指定名称的属性,那么JavaScript中hasOwnProperty函数方法返回 true,反之则返回 false。
[].forEach.call($$(""),function(a){a.style.outline=“1px solid #”+(~~(Math.random()(1<<24))).toString(16)}) 给页面每一个dom元素加上一个彩色border
防抖和节流
针对响应跟不上触发频率这种问题的两种解决方案, 再给dom绑定事件的时候,有些时间我们是无法控制频率的。如鼠标移动事件,滚动事件onscroll,窗口大小改变事件onresize,瞬间的操作都会导致这些事件被高频触发。如果事件的回调函数较为复杂, 就会导致响应跟不上触发,出现页面卡顿、假死现象。针对这种连续触发和不可控的高频触发问题,可以用去抖动和节流。防抖的方法是,当时间触发的时候,设定一个周期延迟执行,若期间又被触发,那么重新设定周期,直到周期结束,执行动作。如果周期内有事件发生,那么周期就重新设定。节流的方法是固定周期内,只执行一次动作,如果有新的事件触发,那么就不执行,周期结束之后,执行动作。
去抖方法一,有新事件触发,就清除旧定时器
// 暴力版: 定时器期间,有新操作时,清空旧定时器,重设新定时器
var debounce = (fn, wait) => {
let timer, timeStamp=0;
let context, args;
let run = ()=>{
timer= setTimeout(()=>{
fn.apply(context,args);
},wait);
}
let clean = () => {
clearTimeout(timer);
}
return function(){
context=this;
args=arguments;
let now = (new Date()).getTime();
if(now-timeStamp < wait){
console.log('reset',now);
clean(); // clear running timer
run(); // reset new timer from current time
}else{
console.log('set',now);
run(); // last timer alreay executed, set a new timer
}
timeStamp=now;
}
}
方法二周期内有新事件触发时,重置定时器开始时间撮,定时器执行时,判断开始时间撮,若开始时间撮被推后,重新设定延时定时器
/ 优化版: 定时器执行时,判断start time 是否向后推迟了,若是,设置延迟定时器
var debounce = (fn, wait) => {
let timer, startTimeStamp=0;
let context, args;
let run = (timerInterval)=>{
timer= setTimeout(()=>{
let now = (new Date()).getTime();
let interval=now-startTimeStamp
if(interval<timerInterval){ // the timer start time has been reset, so the interval is less than timerInterval
console.log('debounce reset',timerInterval-interval);
startTimeStamp=now;
run(timerInterval-interval); // reset timer for left time
}else{
fn.apply(context,args);
clearTimeout(timer);
timer=null;
}
},timerInterval);
}
return function(){
context=this;
args=arguments;
let now = (new Date()).getTime();
startTimeStamp=now;
if(!timer){
console.log('debounce set',wait);
run(wait); // last timer alreay executed, set a new timer
}
}
}
//简单版
function debounce(fn) {
let timeout = null; // 创建一个标记用来存放定时器的返回值
return function () {
clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
fn.apply(this, arguments);
}, 500);
};
}
function sayHi() {
console.log('防抖成功');
}
var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi)); // 防抖
节流方法一
简单版: 定时器期间,只执行最后一次操作
var throttling = (fn, wait) => {
let timer;
let context, args;
let run = () => {
timer=setTimeout(()=>{
fn.apply(context,args);
clearTimeout(timer);
timer=null;
},wait);
}
return function () {
context=this;
args=arguments;
if(!timer){
console.log("throttle, set");
run();
}else{
console.log("throttle, ignore");
}
}
}
//另一种简单版
function throttle(fn) {
let canRun = true; // 通过闭包保存一个标记
return function () {
if (!canRun) return; // 在函数开头判断标记是否为 true,不为 true 则 return
canRun = false; // 立即设置为 false
setTimeout(() => { // 将外部传入的函数的执行放在 setTimeout 中
fn.apply(this, arguments);
// 最后在 setTimeout 执行完毕后再把标记设置为 true(关键) 表示可以执行下一次循环了。当定时器没有执行的时候标记永远是 false,在开头被 return 掉
canRun = true;
}, 500);
};
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi));
节流方法二
/// 增加前缘
var throttling = (fn, wait, immediate) => {
let timer, timeStamp=0;
let context, args;
let run = () => {
timer=setTimeout(()=>{
if(!immediate){
fn.apply(context,args);
}
clearTimeout(timer);
timer=null;
},wait);
}
return function () {
context=this;
args=arguments;
if(!timer){
console.log("throttle, set");
if(immediate){
fn.apply(context,args);
}
run();
}else{
console.log("throttle, ignore");
}
}
}
创建,移除,移动,复制,查找节点
Document.write会导致重绘整个页面,innerHTML只重绘页面的一部分
不在任何函数里定义的变量就具有全局作用域,js有一个全局对象window,全局作用域的变量实际上就是被绑定到window上的一个属性,window对象的内置属性都有全局作用域。 在一个函数里定义的变量就只对这个函数内部可见,这就是函数(局部)作用域
判断两个对象相等, 可以用遍历来做,也可以转换为字符串
Json.strungify(obj) == Json,Stringify(obj2);
用户验证