石家庄手机网站制作,wordpress主题出错,百度关键词搜索量查询,产品网站开发流程28.jquery#xff1a;js库
简化版本的js#xff0c;封装了现成功能的js代码。
jquery就是一些封装好了的现成的方法#xff0c;供我们直接使用。
jquery能实现的js都能实现。
在使用 记得先引入jquery#xff1a;在菜鸟教程上直接用jquery的绝对路径引入#xff0c;jq…28.jqueryjs库
简化版本的js封装了现成功能的js代码。
jquery就是一些封装好了的现成的方法供我们直接使用。
jquery能实现的js都能实现。
在使用 记得先引入jquery在菜鸟教程上直接用jquery的绝对路径引入jquery他自己已经延迟了先显示html在显示功能。
script srchttps://cdn.staticfile.org/jquery/1.10.2/jquery.min.js/script
jquery优点1.市面上仍有些老项目再用2.jquery适合用于小型的项目不用像vue react那样搭建框架3.学习成本低简单易学时间短。
1.常用的选择器
选择器后面跟方法的话他会自动对前面选择器所选择到的每一个元素调用后面的方法自带循环并不是纯粹的返回一个对象返回的是会与后面的方法自动循环相匹配的迭代器。在jquery中基本不用写for循环jQuery不能与原生的js混用(选择器和方法)因为jQuery返回的不是一个元素对象。
$(“*”)选取所有元素
$(“#id”) $(“.class”) $(“p”) $(“h1,div,p”) $(“.intro,.demo”)
$(“选择器:even”)偶数位置的选择器的元素 $(“选择器:odd”)奇数
$(“选择器:first-child”)属于其父元素的第一个选择器 $(“选择器:last-child”) $(“选择器:nth-child(2)”)
$(“ul li:first”) 选取第一个ul元素中的第一个li元素
$(“divp”)div直接子集的所有p $(“div p”) $(“divp”)与div同级的相邻的下一个p $(“div~p”)与div同级的div后面的所有p
$(this) 选取当前html元素
$(“选择器:first”)第一个选择器的元素 $(“选择器:last”)
$(“div:eq(3)”)选中第4个div(从0开始) $(“div:gt(3)”) $(“div:lt(3)”)
应用场景热搜前几条的颜色和后面几条的颜色 2.事件
不能像在js中的$(“#box”).οnclickfunction(){}一样使用事件了因为 jQuery返回的不是对象。
在jQuery中时使用事件时全部去掉on直接用click、focus、blur、mousemove不是赋值而是调用这些方法要做的事情就以函数参数或匿名函数的形式传过去。另外在jQuery中不能直接使用this了要用$(this) $(#box).click(function () { $(this).hide() }) $(“.txt”).on(“click”,”选择器(规定只能添加到指定的子元素上的事件处理程序)”,function(){alert(“被点击了”)}) 等同于js中的 事件对象.addEventListener()类
似于事件委托当时元素本身不存在之后动态添加后再绑定事件。
并且在jq中事件委托时的this指向是准确的不用e.target
ready()该事件在文档就绪后发生当dom加载完毕且页面完全加载时发生ready事件。
$(window).resize()当调整浏览器窗口大小时触发常用于响应式布局。
scroll()滚轮事件前提是必须要有滚动条里面的内容必须要比父级高。 3.效果显示/隐藏的方法有动画
hide(毫秒数/”slow/fast”) show(毫秒数/”slow/fast”) toggle(ms)—自动判断切换隐藏和显示的状态隐藏变显示显示变隐藏。实际上用js就是通过定时器来连续修改宽高。
在隐藏/显示的过程所需要的时间(也可以用fast和slow来控制快慢但工作中常使用毫秒数)。
fadeOut() fadeIn() fadeToggle() 淡出/淡入实现的过程效果不同实际上在js中是通过定时器连续修改透明度。
slideUp() slideDown() slideToggle() 滑动类似卷帘门的效果实际上在js中式通过定时器来连续修改高度。
delay() 对动画效果有延迟
body button idhide隐藏/button button idshow显示/button button idtoggle自动切换/button div classbox/div script $(#hide).click(function () { $(.box).hide(1000) }) $(#show).click(function () { $(.box).show(1000) }) $(#toggle).click(function () { $(.box).toggle(1000)//自动切换显示变隐藏隐藏变显示 }) /script
/body
4. 效果读取/修改样式有动画
在引号中的没有歧义该用横线用横线在引号外的要用驼峰。
修改单个样式css(“属性名”,”属性值”)
读取单个样式css(“属性名”) 内部样式和外部样式的也可以拿到在之前的js中很麻烦需要document.defaultView.getComputedStyle(对象名,null)才可以。
修改多个样式css({
属性名:”属性值”;
属性名:”属性值”
})
添加样式一般都用添加/删除类的方法
animate(cssObj,ms) 用法同css方法唯一的不同是他的样式变化都有动画效果的。有动画有过程的去改样式。但是它不支持修改颜色的样式也不支持css3中的transform属性。
5. 效果stop() 停止当前动态效果
显示/隐藏、animate修改样式这些效果会出现多次点击鼠标后再松开时还在继续运行的情况为了解决这种情况可以在有动画之前先把之前存在的动画停止再重新开始这样就只执行了最后一次类似于防抖。
$(#hide).click(function () { $(.box).stop().slideToggle() })
6. 效果jquery允许链式调用
允许你对连续执⾏多个jq⽅法会按照绑定的顺序依次执⾏
注意在使用链式调用时一定要保证操作的主体不能发生变化。
7. 效果jquery的支持callback(回调函数)
回调函数在当前动画100%完成之后执行作为显示/隐藏/animate动画的第二/三个参数出现。 $(#hide).click(function () { $(.box).slideUp(1000, function () { alert(1) }) }) 8.DOM操作相关的方法
1 获取添加内容和属性
读取text() 修改text(“要修改的内容”) 等同于js中的innerText()获取文本内容
html() html(“要修改的内容”)
val() 等同于表单的value
attr(src) 获取或添加属性 等同于setAttribute() getAttribute() attr()与css()的区别css()用于修改和设置元素的style样式属性如color、background-color而attr()用于修改和设置元素标签本身自带的自身的属性如src、href等。
2 添加元素
append(“html代码”) 在被选元素的结尾添加内容 –父子级 等同于appendChild(对象)
prepend() 在被选元素的开头添加内容—父子级
after() 在被选元素之后添加内容---同级
before() 在被选元素之前添加内容---同级
3 删除元素
remove() 删除被选元素及其子元素 想删谁就对谁调用remove()不需要再通过父级去删除了---js:父级对象.removeChild(子元素对象)
empty() 从被选元素中删除子元素把其内容删掉本身还存在
4 css添加移出类名
addClass(“类名”) removeClass(“类名”) toggleClass(“类名”)
可用于动态地增加/删除属性。
5 尺寸
width() height() 元素本身的宽高
innerWidth() innerHeight() 包含内边距padding的宽高
outerWidth() outerHeight() 包含内边距padding和边框border的宽高
outerWidth(true) outerHeight(true) 包含内边距padding、边框border和外边距margin的宽高
9.jq的遍历方法
找父级
parent(空/“选择器”)返回的是所选元素的直接父级/ 如果加上选择器就要求是该选择器的父级。
parents(空/“选择器”) 返回的是所选元素的所有父级/ 如果加上选择器就要求是该选择器的父级。
parentsUntil(“选择器”) 返回的是到固定区间的父级不包含要找到的选择器。
找子级
children(空/.box) 返回的是所选元素的所有直接子级。。
find(div) 这个的选择器必须要有。返回的是所选元素的所有子级。要是想找所有子级的话传 “*“ 即可。
找同级不包含自己的
siblings(空/“css选择器”) 返回的是所选元素的所有同级元素(上下都选中)。
next(空/”选择器”) 返回的是所选元素的紧挨着的下一个同级
nextAll() 返回的是所选元素的所有的下面的同级
nextUntil(“选择器”) 直到下面的某个固定区间内得所有同级不包含要找到的选择器
prev() 返回上一个同级
prevAll() 返回上面的所有同级
prevUntil()直到上面的某个区间内的所有同级
筛选
first()返回被选元素的首个元素。完全等价于前面的 :first 选择器不能传参。
last()
eq(数字1) 索引号从0开始
filter(“选择器”)找到符合指定条件的元素
not(“选择器”)找到除了not里面条件的元素
每个
each(function(){})为每个匹配元素规定要运行的函数。类似于js中内置对象的foreach()对每一项要进行的操作
10. jquery ajax
1 基本内容
$.ajax({
url:”请求地址”,
type:”请求方式get/post”,
data:{key:value,key2:value2},
dataType:”json”,//预期的后端返回的数据类型
timeOut:5000,//请求超时的时间可选
success:function(data){//请求成功后的回调函数
//data就是后端返回的数据
}
error:function(err){//请求失败后的回调函数
}
}) $.get(url,data,function(data){},dataType)
$.post()
如: $.get(https://restapi.amap.com/v3/weather/weatherInfo, {key: e17d487bab9ea0753d34762321979db4,city: $(#city).val(),extensions: all}, function (data) {console.log(data)}, json)
2 使用jq的ajax实现的天气查询案例
!DOCTYPE html
html
head meta charsetUTF-8 titleDocument/title script srchttps://cdn.staticfile.org/jquery/1.10.2/jquery.min.js/script
/head
body input typetext idcity div idtxt/div script $(#city).blur(function () { $.ajax({ url: https://restapi.amap.com/v3/weather/weatherInfo, type: get, data: { key: e17d487bab9ea0753d34762321979db4, city: $(#city).val(), extensions: all }, dataType: json, success: function (data) { console.log(data) } }) }) /script
/body
/html 3 跨域问题
浏览器的同源策略 同协议 同域名 同端⼝号
解决跨域jsonp 请求代理
11.其他属性和方法
index():返回指定元素相对于其他指定元素的index位置。
属性:length返回被选元素的数量常用于判断所选元素是否存在。
hasClass(“类名”)判断该选择器是否存在该类
12.jQuery实战1手风琴菜单(点开一个下拉展开)
【jQuery插件库】 !DOCTYPE html
html head meta charsetUTF-8 titleDocument/title script srchttps://cdn.staticfile.org/jquery/1.10.2/jquery.min.js/script style * { margin: 0; padding: 0; } body { background-color: #2d2c41; } li { list-style: none; } div, li { width: 200px; height: 50px; background-color: #fff; text-align: center; line-height: 50px; color: #b63b4d; } li { background-color: #444359; color: #fff; border: 1px solid #4b4a5e; } ul { display: none; } p { display: inline-block; } .arrow { /* 箭头旋转 */ transform: rotate(90deg); transition: all 1s; } .active { /* //旋转太生硬希望有个动画但是animate不支持css3中的transform属性 */ transform: rotate(270deg); } /style
/head body div p我是一级/p p classarrow/p /div ul li我是1-1/li li我是1-1/li li我是1-1/li li我是1-1/li /ul div p我是二级/p p classarrow/p /div ul li我是2-1/li li我是2-1/li li我是2-1/li li我是2-1/li /ul div p我是三级/p p classarrow/p /div ul li我是3-1/li li我是3-1/li li我是3-1/li li我是3-1/li /ul div p我是四级/p p classarrow/p /div ul li我是4-1/li li我是4-1/li li我是4-1/li li我是4-1/li /ul script //点击谁就显示谁的二级 $(div).click(function () { //如果是先所有的ul收起来再将选中的展开由于每次都先将所有的收起来了下次一定是展开。 // $(ul).slideUp() //正确的应该是将除了当前的ul外其他的收起来 // $(this).next().siblings(ul).stop().slideUp() // $(this).next().stop().slideToggle() $(this).next().stop().slideToggle().siblings(ul).slideUp() //点击让箭头旋转 $(this).children(.arrow).toggleClass(active) // 让除了自己之外的箭头移除旋转 $(this).siblings(div).children(.arrow).removeClass(active) /*bug1:再次点击当前的永远是展开的样子。因为先所有的ul收起来再将选中的展开由于每次都先将所有的收起来了下次一定是展开。 bug2:连续多次点击出现抖动。解决方法再做操作之前先stop() bug3:观察代码发现都是对$(this).next()做操作由于jQuery支持链式调用把他们放在一起写就行。 注意调用的主体不能发生变化第一句是$(this).next().siblings(ul)做操作第二句是对$(this).next()做操作对如果将下面的放到上面则是错误的 注意内联元素不支持旋转动画 注意动画效果的样式animate不支持css3中的transform属性。解决方法使用css3中的动画效果的transition属性 bug4:箭头变化了但回不来。解决方法将要修改的属性写成类自动切换调用该类 bug5:点击自己再点击别人导致全部收起时的箭头有的朝上有的朝下 */ }) /script
/body /html 13.jQuery实战2选项卡 index()找到点击元素所处的位置。
!DOCTYPE html
html head meta charsetUTF-8 titleDocument/title script srchttps://cdn.staticfile.org/jquery/1.10.2/jquery.min.js/script style * { padding: 0; margin: 0; } li { list-style: none; } .tab { float: left; width: 80px; height: 50px; background-color: gray; text-align: center; line-height: 50px; color: white; margin-right: 5px; } .content { width: 335px; height: 300px; background-color: pink; display: none; } .act { display: block; } .red { background-color: red; } /style
/head body div classtab体育新闻/div div classtab科技新闻/div div classtab电影新闻/div div classtab娱乐新闻/div div styleclear: both;/div div div classcontent act p我是体育新闻1/p p我是体育新闻2/p p我是体育新闻3/p /div div classcontent p我是科技新闻1/p p我是科技新闻2/p p我是科技新闻3/p /div div classcontent p我是电影新闻1/p p我是电影新闻2/p p我是电影新闻3/p /div div classcontent p我是娱乐新闻1/p p我是娱乐新闻2/p p我是娱乐新闻3/p /div /div script $(.tab).click(function () { // 所点击元素相对于同类型元素的所在位置 var index $(this).index(.tab) //把除了当前的所有的content隐藏 // $(.content).eq(index).siblings().hide() // //找到与点击元素所对应位置的content设置可见 // $(.content).eq(index).show() $(.content).eq(index).show().siblings().hide() //先把除了自己的菜单颜色都恢复原色 // $(this).siblings(.tab).css(background-color, gray) // //选中谁把谁的菜单的背景色变为红色 // $(this).css(background-color, red $(this).addClass(red).siblings(.tab).removeClass(red) }) /script
/body /html 14.jQuery实战3淘宝筛选菜单(中等以上难度70%) 同系列的只能选择一个在添加元素的时候将所选元素的父级的类名也添加进去添加前先通过length判断下面是否有该系列的若有将其替换若没有直接添加即可。
!DOCTYPE html
html head meta charsetUTF-8 titleDocument/title script srchttps://cdn.staticfile.org/jquery/1.10.2/jquery.min.js/script style * { padding: 0; margin: 0; } li { list-style: none; } .clear { clear: both; } .wrap { width: 800px; margin: auto; margin-top: 100px; } .type, .tag, .tips { float: left; } .tag li { float: left; /* 文字块的大小不要给固定大小要用文字的大小撑开 */ padding: 5px 10px; margin-right: 15px; color: #039; border-radius: 2px; } .tag .act { background-color: #ff6600; color: #fff; } .wrapdiv { margin-bottom: 10px; } li:hover { background-color: #f3edc2; color: #ff6600; } /style
/head body div classwrap div classcoat p classtype上装/p ul classtag li classall act全部/li li针织衫/li li毛呢外套/li liT恤/li li羽绒服/li li棉衣/li li卫衣/li li风衣/li div classclear/div /ul div classclear/div /div div classpants p classtype裤装/p ul classtag li classall act全部/li li牛仔裤/li li小脚/铅笔裤/li li休闲裤/li li打底裤/li li哈伦裤/li div classclear/div /ul div classclear/div /div div classdress p classtype裙装/p ul classtag li classall act全部/li li连衣裙/li li半身裙/li li长袖连衣裙/li li中长款连衣裙/li div classclear/div /ul div classclear/div /div div classselected p classtype已选条件/p p classtips暂时没有选择过滤条件/p ul classtag !-- 在这里的li被清空了当有选择的时候再往里面加 -- /ul div classclear/div /div /div script //点谁谁高亮li的绑定事件只针对当前已经存在的li后面再动态添加的li不会被绑定这些事件 $(li).not(.all).click(function () { //1 实现点击元素高亮 $(this).addClass(act).siblings(li).removeClass(act) //2 将选中项加入到下面的已选条件中 添加元素 //先获取到当前所选项的内容 var txt $(this).text() //获取其父级的类名以便于知道是哪个系列的方便之后限制同类别的不能重复添加 var parName $(this).parent().parent().attr(class) //如果所选板块所属系列在下面没有则直接添加否则就要找到下面对应的元素将其替换 //通过所选元素的length属性判断下面是否有同系列的 if ($(.selected . parName).length) { // 下面已经有了找到并将其文本替换 $(.selected . parName).text(txt) } else { //下面没有直接添加即可 $(.selected .tag).append(li classact parName txt /li) } //目前同系列的可以重复添加要解决这个问题在添加时通过其父级的父级的类名先判断下面有没有这个系列如果有将其替换如果没有直接添加 //3 当ul类名没有li时才显示提示信息若有则不显示提示信息 toggleTips() }) //4 通过全部来做对应项的删除 $(.all).click(function () { var preName $(this).parent().parent().attr(class) $(.selected . preName).remove() //回归高亮状态 $(this).addClass(act).siblings(li).removeClass(act) toggleTips() }) /* 5 通过点击下面的已选条件实现删除 事件直接绑定不了因为这一段代码在一进入页面就执行了但此时获取不到元素。 解决方法事件委托给其父级绑定即可在jq中的on方法 */ $(.selected).on(click, li, function () { $(this).remove() //找到所对应系列的全部回归全部拿到类名可以通过字符串切割split也可以substring var cla $(this).attr(class).split( )[1] //找到其父级的父级类名是cla的全部因为分类中有cla筛选条件中也有cla要将他们加以区分只选择wrap的直接子集的cla //不是找直接子集了找所有子集用find(选择器) $(.wrap. cla).find(.all).addClass(act).siblings(li).removeClass(act) toggleTips() }) //封装筛选条件的提示部分 function toggleTips() { if ($(.selected li).length) { $(.tips).hide() } else { $(.tips).show() } } /script
/body /html
15.jQuery实战4移动端购物车(高难度90%)
圆圈和勾选使用阿里巴巴矢量图标库。
在全选按钮那里有点小坑需要分别使用更新前的勾的数量和更新后的勾的数量。
在遇到问题时通过控制台输出变量、审查元素的class名字的更改。 !DOCTYPE html
html head meta charsetUTF-8 titleDocument/title script srchttps://cdn.staticfile.org/jquery/1.10.2/jquery.min.js/script style .wrap { width: 800px; margin: 100px auto; } .product { border: 1px solid; border-left: none; border-right: none; padding: 20px; } .price { color: red; font-size: 20px; } .pro_name { font-weight: bold; } .total { margin-top: 100px; } .deal { width: 80px; height: 30px; } .act { background-color: #ed535f; color: #fff; } /style
/head body div classwrap div classproduct img classsel un srcimages/unselected.png span classpro_nameiPhone14/span span classprice10000/span button-/button span classcount1/span button/button img srcimages/delete.png classdelete /div div classproduct img classsel un srcimages/unselected.png span classpro_name粉底液/span span classprice300/span button-/button span classcount1/span button/button img srcimages/delete.png classdelete /div div classproduct img classsel un srcimages/unselected.png span classpro_nameps5/span span classprice5000/span button-/button span classcount1/span button/button img srcimages/delete.png classdelete /div div classproduct img classsel un srcimages/unselected.png span classpro_name键盘/span span classprice400/span button-/button span classcount1/span button/button img srcimages/delete.png classdelete /div div classtotal img srcimages/unselected.png span classtotal_select已选(0)/span span classtotal_price0/span button classdeal disabledtrue结算/button /div script /*我的第一步先做圆圈已选个数在切换勾圈时加减已选数量、总金额和结算按钮发生变化 第二步加减按钮数量和总金额变化 第三步已选按钮总金额变化勾圈变化 第三步删除按钮alert弹窗提示删除该行总金额变化 */ /*注意勾圈是否被勾选的判断方法通过类名un al 在更改勾圈的时候也要同时更改其类名un 和 al*/ //1加减号功能 $(.product button).click(function () { var sign $(this).text() var org Number($(this).siblings(.count).text()) if (sign ) { $(this).siblings(.count).text(org 1) } else if (org 1) { $(this).siblings(.count).text(org - 1) } totalPrice() }) //2 点击勾圈事件 $(.product .sel).click(function () { //2-1 实现勾圈的切换 //通过判断是否存在un的类名来判断是否被勾选。已经被勾选的类名为al,未被勾选的类名是un默认是没有被选中的 if ($(this).hasClass(un)) { $(this).attr({ src: images/selected.png, class: sel al }) } else { $(this).attr({ src: images/unselected.png, class: sel un }) } //2-2 已选数量的变化 //通过勾圈的al类名的数量来判断勾选了几个商品 productCount() //2-3 计算总价 totalPrice() }) //3 结算 //封装计算总价的部分勾圈按钮、全选按钮、数量加减按钮、删除按钮在点击时都需要进行计算总价因此将其封装起来。 //我原来的想法是每个部分变化后单独算总价但是总价一定是所有已选商品的单价*数量不会发生变化的哪怕是删掉了在这些商品因此我们计算总价的函数就是 找到所选商品 将其单价*数量 再将所有的相加 function totalPrice() { //找到每一个选中商品用他的 数量*单价再把它们的每个总价求和 //要对每个选中的商品都要求总价要用到循环 //先拿到选中的商品 var total 0;//总价 $(.al).each(function () { var price Number($(this).siblings(.price).text().substring(1)) var count Number($(this).siblings(.count).text()) total price * count }) $(.total_price).text( total) } //封装计算已选商品数量的函数在点击勾圈、删除商品、全选按钮的时候都需要更改已选的数量 function productCount() { //通过勾圈的al类名的数量来判断勾选了几个商品 var len $(.al).length var slen $(.product).length //如果全选了既要更改已选数量也要更改全选按钮 $(.total_select).text(len slen ? 全选 : 已选( len )) $(.total img).attr(src, len slen ? images/selected.png : images/unselected.png) //在实际工作中尽量避免使用if else,显得有点低级像这种两种情况的尽量用三目运算符 // if (len $(.product).length) { // $(.total_select).text(全选) // } else { // $(.total_select).text(已选( len )) // } } //4 垃圾桶 删除后移除当前商品、总价、已选要变化 $(.delete).click(function () { // alert(你确定要删除当前商品) $(this).parent(.product).remove() totalPrice() productCount() }) //5全选功能 有小坑坑坑坑坑坑坑 //在点击全选之前如果全部商品已经被选中则此时全选按钮被勾选将其封装在了判断已选商品数量中了 //若在此时再点击全选按钮则全部取消勾选若商品未被全部勾选则点击全选之后全选按钮被勾且全部商品被勾 //另外已选数量和总价也会发生变化 $(.total img).click(function () { // 判断全选按钮是否要改变使用的是之前的勾圈数量,根据当前勾圈的数量来决定要将其全部换成勾还是全部换成圈 var len $(.al).length//更新前的勾的数量 var slen $(.product).length $(.sel).attr({ src: len slen ? images/unselected.png : images/selected.png, class: len slen ? sel un : sel al }) //判断已选数量我们要使用的是做了全选修改之后的勾圈数量与前面获取到的不一样了 len $(.al).length//更新后的数量, $(.total_select).text(len slen ? 全选 : 已选( len )) $(this).attr(src, len slen ? images/selected.png : images/unselected.png) totalPrice() }) /script
/body /html 16.jQuery实战5抽奖大转盘
缩放background-size:cover;
要是想要让某一个区间内的奖品中将几率大一些可以将这些度数放在数组中中奖概率高的就在数组中多出现几次用二维数组来存储度数。
下次转的角度是要在上次转动角度的基础上再转的否则下次的角度转动会在上次已经转动的基础上小幅度的转动的而我们要求每次转动都必须是3-4圈。
前提要求抽奖转盘的宽和高是一样的否则在旋转时会出现问题。
DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleDocument/title script srchttps://cdn.staticfile.org/jquery/1.10.2/jquery.min.js/script style .bg { width: 600px; height: 600px; background: url(images/bg1.png) no-repeat center; background-size: cover; /* 将图片按等比例缩放 cover 可能图像的部分内容无法显示在背景中 contain 宽高完全适应背景大小 缩放至图像完全显现出来 */ } .start { width: 200px; position: absolute; top: 165px; left: 196px; } .wrap { position: relative; } /style /head body div classwrap div classbg/div img srcimages/start1.png classstart /div script // var startNum 1080 var startNum 0 $(.start).click(function () { //1080-1440 转3-4圈 // var d Math.floor(Math.random() * (1440 - 1080 1)) 1080 // var d Math.floor(Math.random() * (startNum 360 - startNum 1)) startNum//startnUm1080版本 var d Math.floor(Math.random() * (1440 - 1080 1)) 1080 startNum console.log(d) $(.bg).css({ transform: rotate( d deg), transition: all 2s }) startNum d //下次转动角度必须在上次角度的基础上再转动3-4圈。 // startNum d 1080 var deg d % 360 setTimeout(function () { if (deg 0 deg 45) { alert(恭喜您抽中50积分) } else if (deg 90) { alert(恭喜您抽中手表) } else if (deg 135) { alert(恭喜您抽中6积分) } else if (deg 180) { alert(恭喜您抽中100元红包) } else if (deg 225) { alert(恭喜您抽中50元话费券) } else if (deg 270) { alert(恭喜您抽中红包10元) } else if (deg 315) { alert(恭喜您抽中苹果手机一部) } else if (deg 360) { alert(恭喜您抽中30元现金券) } }, 2200) }) /script /body /html 17.jQuery实战5-1增加概率的抽奖大转盘
DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleDocument/title script srchttps://cdn.staticfile.org/jquery/1.10.2/jquery.min.js/script style .bg { width: 600px; height: 600px; background: url(images/bg1.png) no-repeat center; background-size: cover; } .start { width: 200px; position: absolute; top: 165px; left: 196px; } .wrap { position: relative; } /style /head body div classwrap div classbg/div img srcimages/start1.png classstart /div script var arr [[0, 45], [46, 90], [91, 135], [136, 180], [181, 225], [226, 270], [271, 315], [316, 360], [271, 315], [271, 315], [271, 315], [271, 315]] //从0-7是随机其中6是苹果手机8到arr.length-1是苹果手机 var startNum 0//旋转度数初始值 var r 0//随机取数的初始值 $(.start).click(function () { //从0到arr.length-1取数 var random Math.floor(Math.random() * (arr.length - 1 - 0 1)) 0 //从arr[random][0]到arr[random][1]之间再取数 var ran Math.floor(Math.random() * (arr[random][1] - arr[random][0] 1)) arr[random][0]//0-360之间取到的数 var d startNum 1080 (ran - r) //在上次旋转后的基础上先原地转三圈再在上次最后一圈随机值的基础上转到这次的随机取值 $(.bg).css({ transform: rotate( d deg), transition: all 2s }) startNum d r ran var deg d % 360 setTimeout(function () { if (deg 0 deg 45) { alert(恭喜您抽中50积分) } else if (deg 90) { alert(恭喜您抽中手表) } else if (deg 135) { alert(恭喜您抽中6积分) } else if (deg 180) { alert(恭喜您抽中100元红包) } else if (deg 225) { alert(恭喜您抽中50元话费券) } else if (deg 270) { alert(恭喜您抽中红包10元) } else if (deg 315) { alert(恭喜您抽中苹果手机一部) } else if (deg 360) { alert(恭喜您抽中30元现金券) } }, 2200) }) /script /body /html 20. ES6(ES5.0增加了新特性)
1.let 声明的变量没有提升 不允许重复声明 只在块级作⽤域内有效
暂时性死区在⼀个块级作⽤域内如果⽤let声明了某个变量那么该变量就⾃动绑
定了该作⽤域该作⽤域就形成了⼀个封闭的作⽤域。
2.const 声明常量
3.模板字符串 允许换⾏ 可以直接写变量变量要写在${}⾥⾯
4.扩展运算符 ... 将数组或者类数组结构拆分为参数序列
5.函数的扩展 箭头函数 let fn(m){return m}
如果只有⼀个参数可以省略⼩括号如果想返回⼀个值return连同⼤括号⼀起省略如
果要返回⼀个对象的话对象外⾯要套括号避免歧义
箭头函数中的this指向指向的是函数定义时所在的对象
箭头函数不允许当作构造函数也就是不能new
6.变量的解构赋值
let [变量1变量2变量3][值1值2值3]
7.对象的扩展
如果对象的属性值是个变量并且该变量名跟属性名⼀样那么可以省略为⼀个
对象中的函数属性可以省略function
8.对象的解构赋值
let {name,age}{name:⼩红,age:18}
let obj{name:⼩红,age:18,sex:girl,address:北京}function fn({name,age}){console.log(nameage)}fn(obj)
如果出现多层嵌套的对象需要解构 let obj{name:⼩红,age:18,sex:girl, 5 hobby:{sport:{aaa:},movie:⽣化危机}}let {hobby:{sport:{aaa},movie}}obj; 9.Symbol 新的原始数据类型
symbol:类似于字符串的值永远是独⼀⽆⼆的
10.Set 类似与数组的⼀种数据结构
set数据结构值都是唯⼀的
add()
delete()
has()
size()
keys遍历属性名
values()遍历属性值
entries()遍历属性名和属性值的
11.Map类似于对象的⼀种数据结构
1 let mapnew Map([[name,⼩明],[12,18],[[1,2,3],567]])
应该叫值值对
map的属性名不局限于字符串
set(“属性名”,属性值)
get(属性名)取值
has(属性名)
delete(属性名)
clear()
size()
keys遍历属性名
values()遍历属性值
entries()遍历属性名和属性值的 12. Promise
异步编程定时器 ajax
解决⽅案 回调函数
then()⽅法返回的是⼀个全新的promise实例
function fn() {var anew Promise(function(resolve,reject){setTimeout(function(){console.log(666);resolve(haha)},2000)
7
})return a}function fn2(){var bnew Promise(function(resolve,reject){setTimeout(function(){console.log(777);resolve(呵呵)},1000)
17
})return b}
21
fn().then((res){console.log(123,res);return fn2()}).then((res){console.log(99,res)}) 13.async await函数
async 是“异步”的简写⽽ await 可以认为是 async wait 的简写。所以应该很好理解 async ⽤于申明⼀个 function 是异步的⽽ await ⽤于等待⼀个异步⽅法执⾏完成。 async函数会返回⼀个promise对象如果在函数中return⼀个值那么该值会通过
Promise.resolve()传递出去 ⼀般来说都认为 await 是在等待⼀个 async 函数完成。不过按语法说明await 等待的是⼀个表达式这个表达式的计算结果是 Promise 对象或者其它值换句话说就是没有特殊限定。
因为 async 函数返回⼀个 Promise 对象所以 await 可以⽤于等待⼀个 async 函数的返回值⸺这也可以说是 await 在等 async 函数但要清楚它等的实际是⼀个返回值。注意到
await 不仅仅⽤于等 Promise 对象它可以等任意表达式的结果所以await 后⾯实际是可以接普通函数调⽤或者直接量的。所以下⾯这个示例完全可以正确运⾏ await 等到了它要等的东⻄⼀个 Promise 对象或者其它值然后呢我不得不先说 await 是个运算符⽤于组成表达式await 表达式的运算结果取决于它等的东⻄。
如果它等到的不是⼀个 Promise 对象那 await 表达式的运算结果就是它等到的东⻄。
如果它等到的是⼀个 Promise 对象await 就忙起来了它会阻塞后⾯的代码等着 Promise 对象 resolve然后得到 resolve 的值作为 await 表达式的运算结果。
案例 1 function fn() { 2 var anew Promise(function(resolve,reject){ 3 setTimeout(function(){ 4 console.log(666); 5 resolve(haha) 6 },2000) 7 8 }) 9 return a 10 } 11 async function fn2(){ 12 let bawait fn(); 13 console.log(执⾏,b) 14 } 15 fn2() 14.module
14.module语法
(1)export var a1 可以导出任何的变量声明语句或者函数声明语句
export {a,b,fn}
export var a1 ⼀定是完整的变量声明语句
import {a} from ./a.js
(2)改名字
导出 export {原名 as 新名}
引⼊ import {导出的名字 as 新名}
(3)默认导出:从前⾯的例⼦可以看出使⽤import命令的时候⽤户需要知道所要加载的变量名或函数名否则⽆法加载。但是⽤户肯定希望快速上⼿未必愿意阅读⽂档去了解模块有哪些属性和⽅法。
export default:
⼀个⽂件只能有⼀个默认导出
引⼊的时候不需要⼤括号
4整体引⼊
import ./common.css
import ./../js/main.js 易混点
1、变量未声明直接进行了赋值js会自动帮忙声明为全局变量。
变量声明提前当遇到变量声明时会出现将变量声明提前到当前作用域最顶部的情况只是变量声明提前了变量赋值并没有提前。
函数提前函数整体提前到当前作用域的最顶部。
2、关于逻辑运算的返回值问题返回的不只可以是布尔值也可以是正常的数值关键是看输入的内容是什么就行。
3、函数声明方法1function 函数名(形参){
代码段//想⼲的事
}
函数声明方法2(声明变量的方式声明函数)var 函数名function(参数){代码段} 要注意声明和调用的顺序先声明后调用
这两种函数声明的方法实现的效果是一样的但是在函数提升上是不一样的。按照函数方式声明时可以将函数整体提前而按照变量的方式声明的函数只是将函数声明提前了函数的整体并没有提前。因此在使用以函数方式声明的方法时声明与调用的顺序都可以而使用以变量方式声明的方法时一定要先声明后调用否则会出现函数提升的错误。
4、在数组中做判断条件时要将时同一类型的放在else中不是同一类型的不要放在else中。
另外在用if判断时不要一开始就做比较判断先做其他类型的判断因为不是数字类型的数据也是可以做比较大小的如number 和string类型的之间可以进行隐式类型转换。
5、原始数据类型数据之间判断是否相等直接比较大小即可
引用数据类型的数据之间比较是否相等要判断指针是否相等(即使里面的数据是一样的)只有复制赋值的是相等的。
var arr [1, 2, 3, 4] var arr2 [1, 2, 3, 4] console.log(arr arr2)//输出结果false //因为变量中存储的是地址值即指针是不一样的尽管堆中存储的数据是一样的 var arr [1, 2, 3, 4] var arr2 arr console.log(arr2 arr)//输出结果true 如console.log({}{})的结果为false。因为{}是空对象存储的地址是不一样的。
6、js中函数的参数传递是按值传递的只是将变量中要传递的数据或指针复制一份作为实参传给函数原来的数据并不会被修改。
复制的时候复制的是栈里面的内容。
按引用传递实参和形参共用一份数据其中一个对其更改了另一个也会更改。
7、函数也是变量也可以作为实参传递。
var a function () { alert(1) } function fn(a) { a() } fn(a); //结果为弹窗“1” 8、变量代表的是角标还是数据
1对象循环访问变量key代表的是每一个属性名
var obj { name: lili, age: 18, gender: 女 } //变量key代表的是属性名 for (var key in obj) { console.log(key)//输出结果name age gender } for (var key in obj) { console.log(obj[key])//输出结果lili 18 女 }
2内置对象Array对象的map()方法map(function(item,index){return 新值}) 变量item代表的是每一项的数据变量index代表的是角标只有一个参数时代表的是item数据。
var arr [1, 4, 5, 5] var narr arr.map(function (item) { return 星期 item }) console.log(narr) //输出结果[星期1, 星期4, 星期5, 星期5] 9、函数参数是函数的方法数组Array对象的方法
1map(function(item,index){return 新值}) return后的新值就是新数组的每一项返回改变后的新数组
2filter(function(item,index){return 要筛选的条件}) 过滤,返回一个符合指定条件的新数组
3every(function(item,index){return 条件}) 返回布尔值判断是否全部项都满足条件
4some(function(item,index){return 条件}) 返回布尔值判断是否存在有满足条件的项
5forEach(function(item,index){每一项要做的事情}) 循环
6sort(function(a,b){return a-b}) 排序
10、常见坑
数组中删除元素数组长度会变化的情况角标也会发生变化。
解决方法
角标回退倒序循环(也会用到角标回退)
11、想要拿到元素对象的样式时使用 元素对象.属性 只能拿到以行内样式定义的样式而以内部样式和外部样式的形式定义的样式通过该方法并不能拿到。
而 document.defaultView.getComputedStle(要获取样式的元素对象,null) 的返回值是可以拿到元素对象的所有样式。
12、目前使用到了闭包的场景DOM实战2的眼睛flag、定时器中防抖和节流函数的定义。
13、整个前端中遇到的是异步的定时器setTimeout和setIntervalajas、ajax、promise
14、事件
(1) 鼠标的事件onclick onmouseover onmouseout onmousemove
(2) 表单的事件onfocus onblur onchange oninput
(3键盘事件 onkeydown onkeyup onkeypress 用哪一个都可以
(4onreadystatechange ajax请求状态发生变化时触发
15、前后端沟通的注意事项
(1)前端和后端接口的一致性(请求参数的参数名由后端决定的一定要一致)
(2)请求方式是get还是post由后端决定。
16、解决异步的方法回调函数、Promise、await 常用网站菜鸟教程、MDN、iconfont阿里巴巴矢量图标库、jquery插件库 面试题
1、笔试题变量未声明js自动声明为全局变量变量声明提前赋值不提前(a)与(a)的区别的输出结果。
2、 undefined和null的区别⭐⭐⭐面试题
undefined和null都是原始数据类型在布尔运算中被认为是false
undefinedtypeof()是undefined
表示“缺少值”即此处应有值但还没有定义
是JS在运行时创建的全局变量是全局对象的一个属性
nulltypeof()是object本质上是一个对象但是没有指向指向为空。
表示对象的值未设置指示变量未指向任何对象看作是尚未创建的对象
是一个字面量他不是全局对象的一个属性
与对象一样永远不会被JS隐式赋值给变量
常用作函数的参数作为对象原型链的重点。
区别①相等但不全等undefined值是派生自null值的undefined和null都代表着无效的值所以二者相等但由于二者是两种不同的原始数据类型所以不全等。
nullundefined; //true
nullundefined;//false
②typeof()值不同typeof(undefined)为undefined,typeof(null)为null。
③在数字运算中被转化为number类型的值不同null-0;undefined-NaN.
相同点都是原始数据类型保存在栈中变量本地。
数组进行相等比较[]、[null]、[undefined]都隐式转换为’’;对于最里层的[],不管外层嵌套多少个[]最终都可看成只有最里层一个[]. 3、 浅拷贝/浅复制⭐⭐⭐VS深拷贝面试题
浅拷贝对于引用数据类型的数据进行复制赋值时给的都是指针而不是直接给数据。使得他们都拥有相同的指针指向相同的数据这时修改其中一个中的数据另一个的内容也是会受到影响的。这种情况就是浅拷贝。浅拷贝复制的是指针不是数据。
深拷贝复制的是数组里面的数据
JSON的JSON.parse(对象形式的字符串)、JSON.stringify(字符串形式的对象)实现深拷贝把对象转换为字符串类型的基本数据类型的复制本身就是深复制再将复制之后的字符串转换为对象类型这时再修改该对象之前的对象的内容是不会发生变化的。
var obj { hobby: 打篮球, car: bmw }//对象 var a JSON.stringify(obj)//将对象转换为字符出串 var b a//字符串复制基本数据类型的复制本身就是深复制 b JSON.parse(b)//将字符串转换为对象 console.log(b) b.car benz//更改b的carobj的car不受影响 console.log(obj, b) 解决深复制的方法
(1)、JSON.stringfy(字符串类型的对象) JSON.parse(对象类型的字符串)
优点又简单又好用且bug少。
弊端处理不了日期 。日期对象转换为字符串后想再转回对象实现不了
但是在实际开发中基本不会出现属性值为日期的对象使用该方法足够了。
(2)、ES6的扩展运算符该方法只能实现一维的深复制当是二维数组时就实现不了了
let arr [1, 2, 3] let arr2 [...arr] arr[1] hrllo console.log(arr, arr2) // arr:[1, hrllo, 3] arr2:[1, 2, 3] (3)、手写递归实现深复制对对象进行循环复制属性和属性值如果属性值是引用数据类型的数据则对该数据再进行循环复制(使用递归实现)。
优点没有bug可完全实现深复制。
function deepClone(obj) { var obj2 obj instanceof Array ? [] : {} if (obj typeof (obj) object) { for (var key in obj) { if (obj.hasOwnProperty(key)) { if (typeof (obj[key]) object obj[key]) { obj2[key] deepClone(obj[key]) } else { obj2[key] obj[key] } } } } return obj2 } 面试题console.log({}{}) 的结果是false因为{}为空对象其中存储的地址指针是不一样的。什么是闭包闭包有哪些优缺点
内部函数使⽤了外部函数的局部变量这种结构叫闭包函数套函数
优点可以保护变量的/避免全局污染(变量放在全局被不小心篡改)
缺点存在内存泄漏 /内存溢出 。由于闭包中的局部变量始终被全局变量使用着而全局变量是不能销毁的不能被垃圾回收机制清除导致闭包内的局部作用域也无法被垃圾回收机制回收使得内存无法得到释放从而导致内存泄露问题。
关键点是函数fn在全局c中被调用了把返回的函数结果给到了全局变量而全局变量不能被销毁导致fn无法被释放. function fn() { let n 0; return function () { return n } } console.log(fn()())//0 console.log(fn()())//0 console.log(fn()())//0 console.log(fn()())//0 //这种情况下没有导致闭包是因为局部变量fn调用结束之后就被销毁了 function fn() { let n 0; return function () { return n } } let c fn();//这一步是闭包的关键点函数fn被全局变量c一直使用着而全局变量是不能被销毁的导致局部变量fn也不能被销毁内存无法得到释放 console.log(c())//0 console.log(c())//1 console.log(c())//2 console.log(c())//3 6、面试题原题var str”你以为你以为的就是你以为的吗”中一共出现了几次“以为”每次出现的位置在哪要求“以为”每次出现的位置用数组存储。
方法1自己想的每两个字之间判相等需要比较n-1次。
方法2使用内置对象String对象中indexOf(要查找的关键字,从第几位开始找)索引关键字的方法。------更推荐
/* 面试题原题一共出现了几次“以为”每次出现的位置在哪 要求: “以为”每次出现的位置用数组存储 */ //方法一 /*var str 你以为你以为的就是你以为的吗; var num 0 var arr [] var j 0 for (var i 0; i str.length - 1; i) { var nstr str[i] str[i 1] if (nstr 以为) { arr[j] i num j } } console.log(arr, num) //需要比较n-1次*/ //方法二indexOf(要查找的关键字,从第几位开始找)方法 //查找关键字indexOfindexOf只能返回第一次出现的位置想要返回每次出现的位置可以每次从发现“以为”后的位置开始找 var str 你以为你以为的就是你以为的吗以为 var arr []//用来存储“以为”出现的位置 //var num 0;//用来存储“以为”出现的次数 //不用数组的角标了直接用push()的方法往数组的最后加内容 var j 0;//用于存储开始查找的位置 for (var i 0; i str.length; i) { var index str.indexOf(以为, j)//找到/未找到的角标 if (index ! -1) { //找到了“以为” arr.push(index)//将找到位置的角标存入数组 j index 2;//找到了“以为”之后下次开始查找的位置为“以为”后面的内容不能再从头开始查 //num } else { break } //当往后找不到“以为”的时候查找就结束了不用再循环了 } // console.log(num,arr) console.log(arr.length, arr) //输出结果3 [1,4,10] 7、面试题原题数组去重⭐⭐⭐⭐⭐
注意数组长度会变化的情况角标也会发生变化在循环的时候要格外注意角标的变化情况。
从第0项开始每一项都与第0项比较如果二者相等则把后者从数组中使用slice()方法删除这样就保证了第0项在数组中是唯一的再从第1项开始后面的每一项都与第1项比较如果相等则把后者从数组中删除这样就保证了第1项在数组中是唯一的…依次进行比较。
但此时还会存在一些bug在删除重复的数据之后数组长度发生变化它后面数据都会向前移动一位角标会减1这时如果再次进行比较的时候应该从被删除数据的角标开始比较否则会出现跳过一些数据的现象发生。
解决方法一角标回退
每次在删除数据的时候下次在拿数据的时候拿的是被删除数据所在角标的数据。
解决方法二倒序循环
拿最后一项与前面的每一项相比较如果相等则删除前面的项这时即使数组的角标发生变化变化的是后面的前面要拿的项的角标并不会发生变化。
解决方法三indexOf()索引方法循环遍历原数组将新数组中在原数组中没有的数据放入新数组中最后输出新数组。
解决方法四ES6中的Set()自动去重------最简单的方法 //方法一角标回退 var arr [1, 2, 3, 2, 5, 6, 7, 6, 6, 6, a, true, a, a, b, c, false, true] for (var i 0; i arr.length; i) { for (var j i 1; j arr.length; j) { if (arr[i] arr[j]) { arr.splice(j, 1) //如果不j--的话此时的去重并不彻底因为在遇到第一个重复项删除之后j下一个要比较的时候拿到的在原来的数组中占的位置不是i的位置而是靠后一个的位置数组的角标不会跳着显示角标改变会出现有些数据在循环的时候被跳过 j--; //当有重复项时将该项删除后下一次开始比较的时候还是从该项的角标开始比较否则会出现跳过某些项的现象 //在有删除的情况时才进行角标回退 } } } console.log(arr) //方法二倒序循环最后一项 var arr [1, 2, 3, 2, 5, 6, 7, 6, 6, 6, a, true, a, a, b, c, false, true] for (var i arr.length - 1; i 0; i--) { for (var j i - 1; j 0; j--) { if (arr[i] arr[j]) { arr.splice(j, 1) i-- //i--是为了取出的标杆是正确的当删除一个数据之后数组长度发生变化标杆的角标也发生了变化为了之后比较时的标杆不变将标杆的角标-1以便于拿到的标杆在一轮循环中始终是同一个 } } } console.log(arr) //方法三使用indexOf()索引循环遍历原数组如果narr数组中没有该项则把该项放进新数组narr中如果narr数组中有了该项则不放入arr数组中。 var arr [1, 2, 3, 2, 5, 6, 7, 6, 6, 6, a, true, a, a, b, c, false, true] var narr [] for (var i 0; i arr.length; i) { if (narr.indexOf(arr[i]) -1) { narr.push(arr[i]) } } console.log(narr)
//方法四ES6中的Set()自动去重
let arr [1, 2, 3, 2, 5, 6, 7, 6, 6, 6, a, true, a, a, b, c, false, true] let set new Set(arr) console.log([...set])//先拆开再合并 //[1, 2, 3, 5, 6, 7, a, true, b, c, false] 8、将字符串的首字母转为大写后输出字符串切割转数组split拿到数组的某一项的某一位转大写toUpperCase()截取子字符串拼上去数组拼接为字符串 var wordsArr str.split( )//字符串切割转为数组 //对字符数组的每一项进行操作 for (var i 0; i wordsArr.length; i) { //将每个单词的转为大写,并将单词剩余的部分拼接上去 wordsArr[i] wordsArr[i][0].toUpperCase() wordsArr[i].substring(1) } //将数组转换为字符串输出 str wordsArr.join( ) console.log(str) //输出结果Where Are You From ? I Come From China 9、手写防抖和节流函数 //防抖函数封装 function debounce(fn) { var timer null return function () { clearTimeout(timer) timer setTimeout(function () { fn()//要做的事情 }, 1000) } } //节流函数的封装 function throttle(fn) { var flag true//开门 return function () { if (!flag) { //如果是关门则不用再继续了 return } flag false//关门 //1s之后再开门 setTimeout(function () { fn() flag true }, 1000) } } 10、原型与原型链
11、事件触发周期及其执行顺序
12、事件委托/代理
13、服务端返回的状态码404 200(ok) 500 301 304
14、跨域问题及其解决方案
15、改变this指向的方法有有哪些他们之间的区别有哪些。
16、new关键字的原理有哪几步
17、js中的数据类型有几种再加上symbol
18、 实现深拷贝的方法通常有以下几种 1. 手动递归复制对象的所有属性和子对象。这是最基本和常见的深拷贝方法但要求开发者对对象结构和属性进行详细了解并且需要注意循环引用。 2. 使用JSON序列化和反序列化。你可以将对象转换为JSON格式再通过解析JSON格式创建新对象。不过这种方法处理起来相对比较缓慢并且有些对象可能无法被JSON化。 3. lodash库的cloneDeep方法。这是一个JavaScript工具库它提供了一个优秀的深拷贝函数能够方便地对对象进行复制。但使用时需要注意lodash库的导入。 4. jQuery库的extend方法。这个方法可以用来合并多个对象并尝试对对象进行深拷贝。不过需要明确的是这个方法并不总是能够做到完全的深拷贝。 总之每种方法都有其适用的场景和局限性开发者需要根据实际情况选择最合适的实现方法。
1. 手动递归复制对象的所有属性和子对象的方法 js
function deepClone(obj) {
let newObj {};
for (let key in obj) {
if (typeof obj[key] object) {
newObj[key] deepClone(obj[key]);
} else {
newObj[key] obj[key];
}
}
return newObj;
} 2. 使用 JSON 序列化和反序列化的方法 js
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
} 3. 使用第三方库 lodash 的 cloneDeep 方法 js
const lodash require(lodash);
function deepClone(obj) {
return lodash.cloneDeep(obj);
} 4. 使用 jQuery 的 extend 方法 js
const $ require(jquery);
function deepClone(obj) {
return $.extend(true, {}, obj);
} 以上四种方法都可以实现深拷贝但用法和适用场景不尽相同建议根据具体需要选择合适的方法。