
ajax 即 “Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式、快速动态网页应用的技术。早期只有同步的方式,多个请求,只能顺序执行,只能等待执行。有了ajax异步技术,可以无需等待上一个请求执行完成,就可以直接发起请求。服务端返回后,ajax通过回调技术通知客户端程序,把响应的结果传递给用户事先写好的回调函数。通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页进行局部更新,提升网页的效率,用户无需等待页面的刷新,嗖的一下内容就变化了。改变原有整个页面刷新,造成页面晃眼的现象。所以这项技术一出现,就得到业界的推崇。
关键字:异步、回调、局部刷新。
主流方式:

技术栈
用户页面中触发ajax请求,访问后端服务器,Web 中间件 拦截用户请求,转发后端程序进行数据处理,一般还需访问数据库,然后逐层返回。数据库返回数据处理服务,数据处理服务返回Web中间件,Web中间件返回ajax调用,将数据封装到返回的js对象中,目前主流返回数据为json字符串(可以通过Jsonp格式实现跨域访问)。在回调callback的方法中解析json中的数据,最终回显到页面上。通常我们使用jquery封装过的ajax,写法更加简洁灵活。
$.ajax({ //交互方式 $.get,$.post,$.getJSON
async: //请求同步异步,默认true异步
type: //请求类型:GET/POST
url: //请求的网站地址
data: //提交的数据,参数
contentType: //请求的MIME媒体类型:application/x-www-form-urlencoded(默认)、application/json;charset=UTF-8
dataType: //服务器返回MIME类型:xml/html/script/json/jsonp
success: function(data){ //请求成功,回调函数,data封装网站返回的数据
console.log( data );
},
error: function(e){ //请求失败回调函数,e封装错误信息
console.log(e.status); //状态码
console.log(e.responseText); //错误信息
}
})
json请求返回就是json格式,而jsonp请求返回是fun(json)格式。
查询网址:http://p.3.cn/prices/mgets?skuIds=J_1411013,J_1411014
[{"p":"-1.00","op":"3888.00","cbf":"0","id":"J_1411013","m":"6699.00"}, {"p":"-1.00","op":"799.00","cbf":"0","id":"J_1411014","m":"1398.00"}]
查询网址:https://d.3.cn/desc/1411000
通过JSONView插件展示数据:

网站有一个跨域问题,非同一个网站的请求默认是禁止的**(同源策略)**,那我们的页面要访问其他网站啊,例如:我们访问京东获取其商品的价格信息。这时就必须用jsonp方式进行跨域请求。
同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。
json字符串: { "id":"100","name":"tony","salary":"30000" }
js对象: { "id":100,"name":"tony","salary":30000 }
可以看出js对象中value值如果是整数,小数,无需加双引号
Vue中封装了ajax并增强了它,在异步并发处理优于原生ajax。称为:axios(ajax input output system)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="../js/vue.js"></script> //引入js支持,axios.min.js文件 <script src="../js/axios.min.js"></script> </head> <body> <div id="app"> 商品价格:{{info}} </div> </body> <script> new Vue({ el: "#app", data(){ //data的ES6函数写法 return { info : null } }, mounted(){ axios.get('../data/price.json') .then( //箭头函数,res为返回值,res.data 返回的json数据对象 res => ( this.info = res.data.price ) ) .catch(function (e){ console.log(e) }) } }) </script> </html>
注意:
axios请求头的 Content-Type 默认是 application/json,而postman默认的是 application/x-www-form-urlencoded。
ajax一般采用@RequestParam接收参数:
@ResponseBody public Result testpost(@RequestParam String username) {}
axiso采用@RequestBody的json方式接收参数
@ResponseBody public Result testget(@RequestBody Map map) {}
传统 Ajax 指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始js中,核心使用XMLHttpRequest对象,多个请求之间如果有先后关系的话,就会出现回调地狱。
JQuery ajax 是对原生XHR的封装,除此以外还增添了对JSONP的支持。经过多年的更新维护,真的已经是非常的方便了,优点无需多言;如果是硬要举出几个缺点,那可能只有:
Vue2.0之后,尤雨溪推荐大家用axios替换JQuery ajax,想必让axios进入了很多人的目光中。
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,它本身具有以下特征:
防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key,根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多了,参数有点像jQuery ajax。但是,一定记住fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。
总得来说:axios既提供了并发的封装,也没有fetch的各种问题,而且体积也较小,当之无愧现在最应该选用的请求的方式。
转自:csdn 论坛 作者:布诺i
前言
跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号(如存在)相同,则允许相互访问。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源,主要是安全问题。
在很多时候跨域问题我都是让后端解决,嘿嘿。但也有需要自己解决的项目!
首先在项目的根目录下建一个vue.config.js
如下:
//改变webpack的设置
const { default: Axios } = require("axios")
module.exports = {
publicPath :"./",
devServer: {
// 设置主机地址
// host: 'xxx.1xx.1xx.xxx',
// // 设置默认端口
// port: 8051,
// 设置代理
proxy: {
'/api': {
// 目标 API 地址
target: 'http://xxx.xxx.xxx.xxx:8051',//服务器地址
// 如果要代理 websockets
ws: true,
// 将主机标头的原点更改为目标URL
changeOrigin: false
}
}
},
chainWebpack: config => {//没有用到scss的这里就不需要啦!
const oneOfsMap = config.module.rule('scss').oneOfs.store
oneOfsMap.forEach(item => {
item
.use('sass-resources-loader')
.loader('sass-resources-loader')
.options({
// 要公用的scss的路径
resources: './src/assets/base.scss'
})
.end()
})
}
}
转自:csdn 论坛 作者:可 乐 伢
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
因为学习的时候用的版本比较新,而网上的教程又全是老版本,所以出现了很多问题,总结以下,帮同样初学的师傅们踩坑了。
废话不多说:
1:
file->new->project新建一个普通java项目:
工程名可以随意命名
2:
工程名上右键->Add Framework Support:

在Web Application上打勾,点击OK
3:
展开工程名->web->WEB-INF,在WEB-INF下新建两个文件夹,分别是classes、lib:

4:
按下ctrl+alt+shift+S,调出Project Structure,
选到Modules->Paths,单选框选到use module xxxxx,将两个路径改为刚才创建的classes。
然后选到Dependencies,点击下面的+号,选择jars or dirxxxxxxxx,选择刚创建的lib目录,让选择目录用处的话,选择jar direxxxxxxx,打上勾,点击apply,OK
5:
将tomcat/lib目录下的servlet-api.jar复制到我们创建的lib目录里。
6:
点击右上角小锤子旁边的Add Configuration,点击加号,选择tomcat server->local。这里注意不要选成tomEE的,两者图标一样,但是不是一个东西。其他配置不变,点击aplly上面的fix,application context可以随意命名,建议一个/就可以。然后aplly,OK。
7:
改一改index.jsp中带的title和end,运行一下,如果类似以下,那基本就OK了。

8:
在src里面新建一个java class,尝试写一个servlet:
这里也是与其他版本不同的地方,老版本都是import javax.servlet.xxxxx,这里是import jakarta.servlet.xxxxx,具体应该import的包,可以展开servlet-api.jar看到。
import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet(name = "login") public class Login extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML>"); out.println("<HTML>"); out.println(" <HEAD><TITLE>login</TITLE></HEAD>"); out.println(" <BODY>"); out.print(" this is login page"); out.print(this.getClass()); out.println(" </BODY>"); out.println("</HTML>"); out.flush(); out.close(); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML>"); out.println("<HTML>"); out.println(" <HEAD><TITLE>login</TITLE></HEAD>"); out.println(" <BODY>"); out.print(" this is login page"); out.print(this.getClass()); out.println(" </BODY>"); out.println("</HTML>"); out.flush(); out.close(); } }
然后修改web.xml文件,如下:
servlet-name可以任意命名,只要上下两个一致就可以,servlet-class应该与类名相同,url-pattern是与java class中的@WebServlet(name=“xxxx”)的xxxx相同,这里的xxxx就是路径。
此时编译并运行,在地址栏输入我们写的url,就可以访问到动态资源了:

全篇结束,只是记录踩坑,希望能对大家有帮助。
转自:csdn 论坛 作者:Hausa_
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
function _getValue(target, valuePath, defalutVal) {
let valueType = Object.prototype.toString.call(target)
console.log(valueType)
// if (valueType == "[object Array]") {
let paths = valuePath.replace(/\[(\d+)\]/, `.$1`).split('.')
let result = target
for(const path of paths){
result = Object(result)[path]
if(result == undefined){
return defalutVal
}
}
return result
}
测试:
let obj = {
a:{
b:[
{
c:2
}
]
}
}
console.log(_getValue(obj, 'a.b[0].c')) //2
function isEqual(res1, res2) {
let a = getTypeOf(res1)
let b = getTypeOf(res2)
if(a !== b){
return false
}else if(a === 'base'){
console.log('base',res1,res2)
return res1 === res2
} else if(a === 'array'){
if(res1.length !== res2.length){
console.log('array',res1,res2)
return false
}else{
//遍历数组的值比较
for(let i =0;i<res1.length;i++){
if(!isEqual(res1[i],res2[i])){
console.log('array',res1[i],res2[i])
return false
}
}
return true
}
return true
}else if(a === 'object'){
let ak = Object.keys(a)
let bk = Object.keys(b)
if(ak.length !== bk.length){
return false
}else{
for(let o in res1){
console.log(res1[o])
if(!isEqual(res1[o],res2[o])){
console.log('object',res1[o],res2[o])
return false
}
}
return true
}
}else if(a === 'null' || a === 'undefined'){
console.log('null')
return true
}else if(a === 'function'){
console.log('function')
return a === b
}
}
function getTypeOf(res) {
let type = Object.prototype.toString.call(res)
switch (type) {
case "[object Array]":
return 'array'
case "[object Object]":
return 'object'
case "[object Null]":
return 'null'
case "[object Undefined]":
return 'undefined'
case "[object Number]"||"[object String]"||"[object Boolean]":
return 'base'
case "[object Function]":
return 'function'
default:
return 'typeError'
}
}
测试:
let a = {
a:20,
b:{
c:30,
d:[1,2,3]
}
}
let b = {
a:20,
b:{
c:30,
d:[1,2,3]
}
}
console.log(isEqual(a,b)) //true
function _flat(arr){
let result = []
for(let i = 0;i<arr.length;i++){
if(Array.isArray(arr[i])){
result = result.concat(_flat(arr[i]))
}else{
result.push(arr[i])
}
}
return result;
}
let arr = [1,2,[3,4,[5,6]]]
_flat(arr) //[1,2,3,4,5,6]
//es6
function _flat2(arr){
while(arr.some(item=>Array.isArray(item))){
arr = [].concat(...arr)
}
return arr
}
let arr = [1,2,[3,4,[5,6]]]
_flat2(arr) //[1,2,3,4,5,6]
简单深克隆,不考虑内置对象和函数
function deepClone(obj){
if(typeof obj !== 'object') return
let newObj = obj instanceof Array?[]:{}
for(let key in obj){
if(obj.hasOwnProperty(key)){
newObj[key] = typeof obj[key] === 'object'?deepClone(obj[key]):obj[key]
}
}
return newObj
}
复杂版深度克隆 考虑内置对象 比如date regexp 函数 以及对象的循环引用的问题
const isObject = (target) => typeof target === "object"&& target !== null;
function deepClone2(target, map = new WeakMap()) {
console.log(target)
if (map.get(target)) {
return target;
}
// 获取当前值的构造函数:获取它的类型
let constructor = target.constructor;
// 检测当前对象target是否与正则、日期格式对象匹配
if (/^(RegExp|Date)$/i.test(constructor.name)) {
// 创建一个新的特殊对象(正则类/日期类)的实例
return new constructor(target);
}
if (isObject(target)) {
map.set(target, true); // 为循环引用的对象做标记
const cloneTarget = Array.isArray(target) ? [] : {};
for (let prop in target) {
if (target.hasOwnProperty(prop)) {
cloneTarget[prop] = deepClone(target[prop], map);
}
}
return cloneTarget;
} else {
return target;
}
}
filter去重
function _unique(arr){
return arr.filter((item,index,array)=>{
return array.indexOf(item) === index
})
}
es6 Set
function _unique2(arr){
return [...new Set(arr)]
}
includes
function _unique3(arr){
let newArr = []
arr.forEach(item => {
if(!newArr.includes(item)){
newArr.push(item)
}
});
return newArr
}
双层for循环
function _unique4(arr){
for(let i =0;i<arr.length;i++){
for(let j =i+1;j<arr.length;j++){
if(arr[i] === arr[j]){
arr.splice(j,1)
j--
}
}
}
return arr
}
indexof
function _unique5(arr){
let newArr = []
for(let i = 0;i<arr.length;i++){
if(newArr.indexOf(arr[i] === -1){
newArr.push(arr[i])
})
}
return newArr
}
function _typeOf(obj){
let res = Object.prototype.toString.call(obj).split(' ')[1]
let mold = res.substring(0,res.length-1).toLowerCase()
return mold
}
_typeOf(5) //number
_typeOf('5') //string
function getParamsObj(params){
let paramsStr = params.replace(/^.+\?(.+)/,"$1")
let paramsArr = paramsStr.split('&')
let paramsObj = {}
for(let [key,value] of paramsArr.entries()){
if(/=/.test(value)){
let valArr = value.split('=')
val = decodeURIComponent(valArr[1]) //解码
val = /^\d+$/.test(val)?parseFloat(val):val //判断是不是数字
if(paramsObj.hasOwnProperty(valArr[0])){
paramsObj[valArr[0]] = [].concat(paramsObj[valArr[0]],val)
}else{
paramsObj[valArr[0]] = val
}
}
}
return paramsObj
}
//从一次传入多个参数 编程多次调用每次传入一个参数
function add(a, b, c, d, e) {
return a + b + c + d + e
}
function curry(fn) {
let dFn = (...args)=>{
if(args.length == fn.length) return fn(...args)
return (...arg)=>{
return dFn(...args,...arg)
}
}
return dFn
}
let addCurry = curry(add)
addCurry(1,2,3)(2)(3)
//添加了两个功能
// 图片加载完成后 移除事件监听
// 加载完的图片从imgList中移除
let imgList = [...document.querySelectorAll('img')]
let length = imgList.length
const imgLazyLoad = function () {
let count = 0
let deleteIndexList = []
imgList.forEach((img, index) => {
let rect = img.getBoundingClientRect()
//获取元素到视图的距离 top元素上边到视图上边的距离 left元素左边到视图左边的距离 right... bottom...
if (rect.top < window.innerHeight) {
// img.src = img.dataset.src
img.src = img.getAttribute('data-src')
deleteIndexList.push(index)
count++
if (count === length) {
document.removeEventListener('scroll', imgLazyLoad)
}
}
})
imgList = imgList.filter((img, index) => !deleteIndexList.includes(index))
}
imgLazyLoad()
document.addEventListener('scroll', imgLazyLoad)
图片懒加载:https://juejin.cn/post/6844903856489365518#heading-19
函数防抖 触发高频事件 事件在n后执行,如果n秒钟重复执行了 则时间重置
//简易版
function debounce(func,wait){
let timer;
return function(){
let context = this;
let args = arguments;
console.log(timer)
clearTimeout(timer)
timer = setTimeout(function(){
func.apply(context,args)
},wait)
}
}
let btn = document.querySelector('button');
function aa(){
console.log(111)
}
btn.onclick = debounce(aa,2000)
// 复杂版
// 1.取消防抖
// 2.立即执行功能(点击之后立即执行函数 但是 wait时间之后在点击才能在立即执行)
// 3.函数可能有返回值
function debounce(func,wait,immediate){
let timer,result;
const debounce = function () {
const context = this
const args = arguments
if(timer) clearTimeout(timer)
if(immediate){
console.log(timer)
var callNow = !timer
timer = setTimeout(function () {
timer =null
},wait)
if(callNow) result = func.apply(context,args)
}else{
timer = setTimeout(function (params) {
result = func.apply(context,args)
},wait)
}
return result
}
debounce.cance = function () {
clearTimeout(timer)
timer=null
}
return debounce
}
let btn = document.querySelector('button');
function aa(){
console.log(111)
}
btn.onclick = debounce(aa,2000,true)```
函数节流 触发高频事件 且n秒只执行一次
//使用时间戳
function throttle(func,wait) {
var context,args;
var previous = 0
return function () {
context = this;
args = arguments;
let nowDate = +new Date()
if(nowDate-previous>wait){
func.apply(context,arguments)
previous = nowDate
}
}
}
//定时器
function throttle(func,wait) {
var context,args;
var timer;
return function(){
context = this;
args = arguments;
if(!timer){
timer = setTimeout(function () {
timer = null;
func.apply(context,args)
},wait)
}
}
}
//组合版 options.leading 为true 立即执行一次 options.trailing为true 结束之后执行一次 默认为true function throttle(func, wait ,options = {}) { var context, args, timer,result; var previous = 0; var later = function () { previous = options.leading === false ? 0 : new Date().getTime(); timer = null; func.apply(context, args) if (!timer) context = args = null; } var throttle = function () { var now = new Date().getTime() if (!previous && options.leading === false) previous = now; context = this; args = arguments; //下次触发 func 剩余的时间 var remaining = wait - (now - previous); if (remaining <= 0 || remaining > wait) { // if (timer) { // clearTimeout(timer); // timer = null; // } previous = now; func.apply(context, args); if (!timer) context = args = null; } else if (!timer&& options.trailing !== false) { timer = setTimeout(later, remaining); } } throttled.cancel = function() { clearTimeout(timer); previous = 0; timer = null; } return throttle } function aa(e) { console.log(111) console.log(e) } let btn = document.querySelector('button'); btn.onclick = throttle(aa, 2000,{ leading:false, trailing:true
})
转自:csdn论坛 作者:Selfimpr欧
1.Object.defineProperty(obj,prop,descriptor)这个语法内有三个参数,分别是obj(要定义其上属性的对象) prop (要定义或修改的属性)descriptor (具体的改变方法)
2.简单的说 就是用这个方法来定义一个值。当调用时我们使用了它里面的get方法,当我们给这个属性赋值的时候,又用到了它里面的set方法
var obj = {}; Object.defineProperty(obj,'hello',{ get: function(){ console.log('调用了get方法') }, set: function(newValue){ console.log('调用了set方法,方法的值是' + newValue); } }); obj.hello; // => '调用了get方法' obj.hello = 'hi'; // => '调用了set方法,方法的值是hi'
原文来自于这里,我说一下我自己的理解,其实发布-订阅模式和观察者模式很像,但是不同的是,观察者模式只有两个角色,而且Obsever是知道Subject的,但是在发布-订阅模式中,他们两却彼此不了解,他们是在一种类似于中间件的帮助下进行通信的,换句话说,还有第三个组件,称为代理或消息代理或事件总线,Observer和Subject都知道该组件,该组件过滤所有传入消息并相应的分发他们。
<input type="text"> <p></p>
我们要对上面两个DOM元素实现双向数据绑定,就是当输入inputValue时下面的p可以及时更新inputValue内容
<script> let input = document.querySelector('input') let p = document.querySelector('p') let obj = {} let value = '' Object.defineProperty(obj, 'inputvalue', { get() { return value }, set(newValue) { input.value = newValue
p.innerHTML = newValue } }) // 订阅者 DOM元素 input.value = obj.inputvalue
p.innerHTML = obj.inputvalue // 监听输入的事件 input.addEventListener('keyup', function (e) { // 修改inputvalue 达到修改input.value 以及input.innerHTML // 发布者 obj.inputvalue = e.target.value // 触发了set }) </script>
所以在我们的代码中,订阅者就是页面中的DOM元素,因为他会订阅我们的inputvalue,而发布者就是监听事件中的数据,一旦监听到了数据有修改,就要发布给我们的订阅者,也就是说输入的数据一旦发生了变化,我们的页面DOM元素的数据也会发生变化,所以这个中间件就是Object.defineProperty中的set方法
转自:csdn 论坛 作者:Y shǔ shǔ
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
一、程序设计语言中的两大编程思想:面向对象、面向过程
(一)、面向过程
(二)、面向对象
(三)、什么是对象?
自定义对象的方式主要有以下几种:
字面量形式、工厂形式、构造方法
(四)、字面量形式的创建
格式:
var 对象名称={ 属性名称1:属性,1,
属性名称2:属性值2,
属性名称3:属性值3,
属性名称n:属性值n, };
沙场练兵:
<!-- 创建一个汽车对象 1、属性:品牌、价格、颜色等、 2、方法(功能):跑、停 --> <body> <script> var car = { brand: '宝马', price: '100万', color: 'red', run: function() { console.log('汽车跑起来了'); }, stop: function() { console.log('汽车停下来了'); } }; console.log(car); </script>
<script> var person = { name: '小王', age: '18', gender: '女', eat: function() { console.log('方便面'); }, play: function() { console.log('王者荣耀'); }, study: function() { console.log('web前端'); } }; console.log(person); </script>
转自:csdn论坛 作者:乘风破浪的程序媛
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
事情是这样的:大家都知道“内存泄露”这回事吧。它有几个常见的场景:
内存泄漏需要重视,它是如此严重甚至会导致页面卡顿,影响用户体验!
其中第 3 点引起了我的注意 —— 我当然清楚地知道它说的是比如:“假设你手动移除了某个dom节点,本应释放该dom节点所占用的内存,但却因为疏忽导致某处代码仍对该被移除节点有引用,最终导致该节点所占内存无法被释放”的情况
<div id="root"> <div class="child">我是子元素</div> <button>移除</button> </div> <script> let btn = document.querySelector('button') let child = document.querySelector('.child') let root = document.querySelector('#root') btn.addEventListener('click', function() { root.removeChild(child) }) </script>
该代码所做的操作就是点击按钮后移除.child的节点,虽然点击后,该节点确实从dom被移除了,但全局变量child仍对该节点有引用,所以导致该节点的内存一直无法被释放。
解决办法:我们可以将对.child节点的引用移动到click事件的回调函数中,那么当移除节点并退出回调函数的执行上文后就会自动清除对该节点的引用,自然也就不会存在内存泄漏的情况了。(这实际上是在事件中实时检测该节点是否存在,如果不存在则浏览器必不会触发remove函数的执行)
<div id="root"> <div class="child">我是子元素</div> <button>移除</button> </div> <script> let btn = document.querySelector('button') btn.addEventListener('click', function() { let child = document.querySelector('.child') let root = document.querySelector('#root') root.removeChild(child) }) </script>
这段代码很完美么?不。因为它在每次事件触发后都创建了对child和root节点的引用。消耗了内存(你完全可以想象一些人会狂点按钮的情况…)。
其实还有一种办法:我们在click中去判断当前root节点中是否还存在child子节点,如果存在,则执行remove函数,否则什么也不做!
这就引发了标题中所说的行为。
怎么判断?
遍历?不,太过麻烦!
不知怎的,我突然想到了 for...in 中的 in 操作符,它可以基于原型链遍历对象!
我们来还原一下当时的场景:打开GitHub,随便找一个父节点,并获取它:

图中画红框的就是我们要取的父元素,橘红色框的就是要判断是否存在的子元素。
let parent=document.querySelector('.position-relative'); let child=document.querySelector('.progress-pjax-loader');
这里注意,因为获取到的是DOM节点(类数组对象),所以我们在操作前一定要先处理一下:
let p_child=[...parent.children];

然后
console.log(child in p_child);

!!!
为什么呢?(此时笔者还没有意识到事情的严重性)
我想,是不是哪里出了问题,用es6的includes API验证一下:
console.log(p_child.includes(child));

没错啊!
再用一般的数组验证一下:

???
此时,笔者才想起到MDN上查阅一番:

进而我发现:in操作符单独使用时它检测的是左侧的值(作为索引)对应的值是否在右侧的对象内部(属性 & 原型上)!
回到上面的代码中,我们发现:

这验证了我们的结论。
很显然,“子元素”并不等同于“存在于原型链上” —— 这又引出了一个知识点:attribute和property的区别!
所以经过一番“折腾”,源代码还是应该直接这样写:
<div id="root"> <div class="child">我是子元素</div> <button>移除</button> </div> <script> let btn = document.querySelector('button') let child = document.querySelector('.child') let root = document.querySelector('#root') let r_child = [...root.children] btn.addEventListener('click', function() { if(r_child.includes(child)){ // 或者你这里直接判断child是否为null也可以...吧 root.removeChild(child) } }) </script>
转自:csdn论坛 作者:恪愚
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
本章将专门介绍与执行上下文创建阶段直接相关的最后一个细节——this是什么?以及它的指向到底是什么。
也许你在其他面向对象的编程语言曾经看过this,也知道它会指向某个构造器(constructor)所建立的对象。但事实上在JavaScript里面,this所代表的不仅仅是那个被建立的对象。
先来看看ECMAScript 标准规范对this 的定义:
「The this keyword evaluates to the value of the ThisBinding of the current execution context.」
「this 这个关键字代表的值为当前执行上下文的ThisBinding。」
然后再来看看MDN 对this 的定义:
「In most cases, the value of this is determined by how a function is called.」
「在大多数的情况下,this 其值取决于函数的调用方式。」
好,如果上面两行就看得懂的话那么就不用再往下看了,Congratulations!
… 我想应该不会,至少我光看这两行还是不懂。
先来看个例子吧:
var getGender = function() {
return people1.gender;
};
var people1 = {
gender: 'female',
getGender: getGender
};
var people2 = {
gender: 'male',
getGender: getGender
};
console.log(people1.getGender()); // female
console.log(people2.getGender()); // female
what?怎么people2变性了呢,这不是我想要的结果啊,为什么呢?
因为getGender()返回(return)写死了people1.gender的关系,结果自然是’female’。
那么,如果我们把getGender稍改一下:
var getGender = function() {
return this.gender;
};
这个时候,你应该会分别得到female与male两种结果。
所以回到前面讲的重点,从这个例子可以看出,即便people1与people2的getGender方法参照的都是同一个getGender function,但由于调用的对象不同,所以执行的结果也会不同。
现在我们知道了第一个重点,**this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数的调用方式。**如何的区分this呢?
看完上面的例子,还是有点似懂非懂吧?那接下来我们来看看不同的调用方式对 this 值的影响。
情况一:全局对象&调用普通函数
在全局环境中,this 指向全局对象,在浏览器中,它就是 window 对象。下面的示例中,无论是否是在严格模式下,this 都是指向全局对象。
var x = 1
console.log(this.x) // 1
console.log(this.x === x) // true
console.log(this === window) // true
如果普通函数是在全局环境中被调用,在非严格模式下,普通函数中 this 也指向全局对象;如果是在严格模式下,this 将会是 undefined。ES5 为了使 JavaScript 运行在更有限制性的环境而添加了严格模式,严格模式为了消除安全隐患,禁止了 this 关键字指向全局对象。
var x = 1
function fn() {
console.log(this); // Window 全局对象
console.log(this.x); // 1
}
fn();
使用严格模式后:
"use strict" // 使用严格模式
var x = 1
function fn() {
console.log(this); // undefined
console.log(this.x); // 报错 "Cannot read property 'x' of undefined",因为此时 this 是 undefined
}
fn();
情况二:作为对象方法的调用
我们知道,在对象里的值如果是原生值(primitive type;例如,字符串、数值、布尔值),我们会把这个新建立的东西称为「属性(property)」;如果对象里面的值是函数(function)的话,我们则会把这个新建立的东西称为「方法(method)」。
如果函数作为对象的一个方法时,并且作为对象的一个方法被调用时,函数中的this指向这个上一级对象。
var x = 1
var obj = {
x: 2,
fn: function() {
console.log(this);
console.log(this.x);
}
}
obj.fn()
// obj.fn()结果打印出;
// Object {x: 2, fn: function}
// 2
var a = obj.fn
a()
// a()结果打印出:
// Window 全局对象
// 1
在上面的例子中,直接运行 obj.fn() ,调用该函数的上一级对象是 obj,所以 this 指向 obj,得到 this.x 的值是 2;之后我们将 fn 方法首先赋值给变量 a,a 运行在全局环境中,所以此时 this 指向全局对象Window,得到 this.x 为 1。
我们再来看一个例子,如果函数被多个对象嵌套调用,this 会指向什么。
var x = 1
var obj = {
x: 2,
y: {
x: 3,
fn: function() {
console.log(this); // Object {x: 3, fn: function}
console.log(this.x); // 3
}
}
}
obj.y.fn();
为什么结果不是 2 呢,因为在这种情况下记住一句话:this 始终会指向直接调用函数的上一级对象,即 y,上面例子实际执行的是下面的代码。
var y = {
x: 3,
fn: function() {
console.log(this); // Object {x: 3, fn: function}
console.log(this.x); // 3
}
}
var x = 1
var obj = {
x: 2,
y: y
}
obj.y.fn();
对象可以嵌套,函数也可以,如果函数嵌套,this 会有变化吗?我们通过下面代码来探讨一下。
var obj = {
y: function() {
console.log(this === obj); // true
console.log(this); // Object {y: function}
fn();
function fn() {
console.log(this === obj); // false
console.log(this); // Window 全局对象
}
}
}
obj.y();
在函数 y 中,this 指向了调用它的上一级对象 obj,这是没有问题的。但是在嵌套函数 fn 中,this 并不指向 obj。嵌套的函数不会从调用它的函数中继承 this,当嵌套函数作为函数调用时,其 this 值在非严格模式下指向全局对象,在严格模式是 undefined,所以上面例子实际执行的是下面的代码。
function fn() {
console.log(this === obj); // false
console.log(this); // Window 全局对象
}
var obj = {
y: function() {
console.log(this === obj); // true
console.log(this); // Object {y: function}
fn();
}
}
obj.y();
情况三:作为构造函数调用
我们可以使用 new 关键字,通过构造函数生成一个实例对象。此时,this 便指向这个新对象。
var x = 1;
function Fn() {
this.x = 2;
console.log(this); // Fn {x: 2}
}
var obj = new Fn(); // obj和Fn(..)调用中的this进行绑定
console.log(obj.x) // 2
使用new来调用Fn(..)时,会构造一个新对象并把它(obj)绑定到Fn(..)调用中的this。还有值得一提的是,如果构造函数返回了非引用类型(string,number,boolean,null,undefined),this 仍然指向实例化的新对象。
var x = 1
function Fn() {
this.x = 2
return {
x: 3
}
}
var a = new Fn()
console.log(a.x) // 3
因为Fn()返回(return)的是一个对象(引用类型),this 会指向这个return的对象。如果return的是一个非引用类型的值呢?
var x = 1
function Fn() {
this.x = 2
return 3
}
var a = new Fn()
console.log(a.x) // 2
情况四:call 和 apply 方法调用
如果你想改变 this 的指向,可以使用 call 或 apply 方法。它们的第一个参数都是指定函数运行时其中的this指向。如果第一个参数不传(参数为空)或者传 null 、undefined,默认 this 指向全局对象(非严格模式)或 undefined(严格模式)。
var x = 1;
var obj = {
x: 2
}
function fn() {
console.log(this);
console.log(this.x);
}
fn.call(obj)
// Object {x: 2}
// 2
fn.apply(obj)
// Object {x: 2}
// 2
fn.call()
// Window 全局对象
// 1
fn.apply(null)
// Window 全局对象
// 1
fn.call(undefined)
// Window 全局对象
// 1
使用 call 和 apply 时,如果给 this 传的不是对象,JavaScript 会使用相关构造函数将其转化为对象,比如传 number 类型,会进行new Number()操作,如传 string 类型,会进行new String()操作,如传 boolean 类型,会进行new Boolean()操作。
function fn() {
console.log(Object.prototype.toString.call(this))
}
fn.call('love') // [object String]
fn.apply(1) // [object Number]
fn.call(true) // [object Boolean]
call 和 apply 的区别在于,call 的第二个及后续参数是一个参数列表,apply 的第二个参数是数组。参数列表和参数数组都将作为函数的参数进行执行。
var x = 1
var obj = {
x: 2
}
function Sum(y, z) {
console.log(this.x + y + z)
}
Sum.call(obj, 3, 4) // 9
Sum.apply(obj, [3, 4]) // 9
情况五:bind 方法调用
调用 f.bind(someObject) 会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,新函数的 this 会永久的指向 bind 传入的第一个参数,无论这个函数是如何被调用的。
var x = 1
var obj1 = {
x: 2
};
var obj2 = {
x: 3
};
function fn() {
console.log(this);
console.log(this.x);
};
var a = fn.bind(obj1);
var b = a.bind(obj2);
fn();
// Window 全局对象
// 1
a();
// Object {x: 2}
// 2
b();
// Object {x: 2}
// 2
a.call(obj2);
// Object {x: 2}
// 2
在上面的例子中,虽然我们尝试给函数 a 重新指定 this 的指向,但是它依旧指向第一次 bind 传入的对象,即使是使用 call 或 apply 方法也不能改变这一事实,即永久的指向 bind 传入的第一次参数。
情况六:箭头函数中this指向
值得一提的是,从ES6 开始新增了箭头函数,先来看看MDN 上对箭头函数的说明
An arrow function expression has a shorter syntax than a function expression and does notbind its own
this,arguments,super, ornew.target. Arrow functions are always anonymous. These function expressions are best suited for non-method functions, and they cannot be used as constructors.
这里已经清楚了说明了,箭头函数没有自己的this绑定。箭头函数中使用的this,其实是直接包含它的那个函数或函数表达式中的this。在前面情况二中函数嵌套函数的例子中,被嵌套的函数不会继承上层函数的 this,如果使用箭头函数,会发生什么变化呢?
var obj = {
y: function() {
console.log(this === obj); // true
console.log(this); // Object {y: function}
var fn = () => {
console.log(this === obj); // true
console.log(this); // Object {y: function}
}
fn();
}
}
obj.y()
和普通函数不一样,箭头函数中的 this 指向了 obj,这是因为它从上一层的函数中继承了 this,你可以理解为箭头函数修正了 this 的指向。所以箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this。
换句话说,箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window。
var obj = {
y: () => {
console.log(this === obj); // false
console.log(this); // Window 全局对象
var fn = () => {
console.log(this === obj); // false
console.log(this); // Window 全局对象
}
fn();
}
}
obj.y()
上例中,虽然存在两个箭头函数,其实this取决于最外层的箭头函数,由于obj是个对象而非函数,所以this指向为Window全局对象。
同 bind 一样,箭头函数也很“顽固”,我们无法通过 call 和 apply 来改变 this 的指向,即传入的第一个参数被忽略。
var x = 1
var obj = {
x: 2
}
var a = () => {
console.log(this.x)
console.log(this)
}
a.call(obj)
// 1
// Window 全局对象
a.apply(obj)
// 1
// Window 全局对象
上面的文字描述过多可能有点干涩,那么就看以下的这张流程图吧,我觉得这个图总结的很好,图中的流程只针对于单个规则。
本篇文章介绍了 this 指向的几种情况,不同的运行环境和调用方式都会对 this 产生影响。总的来说,函数 this 的指向取决于当前调用该函数的对象,也就是执行时的对象。在这一节中,你需要掌握:
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务


此时下载的文件为完整不压缩的开发版本。如果在开发环境下,推荐使用该版本,因为该版本中包含所有常见错误相关的警告。如果在生产环境下,推荐使用压缩后的生产版本,因为使用生产版本可以带来比开发环境下更快的速度体验。
<script type="text/javascript" src="JS/vue.js"></script>
注意:引入Vue.js的 script 标签,必须放在所有的自定义脚本文件的script 之前,否则在自定义的脚本代码中应用步到Vue.js。
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.js"></script>
注意:为了防止出现外部CDN文件不可用的情况,还是建议用户将Vue.js下载到本地计算机中。
npm install vue
注意:使用NPM方法安装Vue.js需要在计算机中安装node.js。
node;js官网:https://nodejs.org/en/,通过node.js官网下载之后,傻瓜式安装即可。
利用Vue.js进行前端框架开发的常用工具有如下几个:WebStorm、IDEA、Vscode
前端框架开发常用的工具下载:
(1)WebStorm官网:https://www.jetbrains.com/webstorm/
(2)IDEA官网:https://www.jetbrains.com/idea/
(3)Vscode官网:https://vscode.en.softonic.com/
转自:csdn 作者:小白_xm
概念:数组是一组数据的集合,其中每一个数据称为数组元素,js的数组可以放任意数据类型的元素,数组是一种将一组数据元素存储在单个变量名下的优雅方式。
示例解释:
//普通变量名只能存一个数据 var num = 10 //数组存储一组数据 var arr = [1,2,3,4,5,'a','b','c']
数组的创建方式:
1、通过new关键字创建(不常用)
//注意A要大写 var 数组名 = new Array() var arr = new Array()//创建一个空数组 var arr = new Array(5)//创建一个长度为5的空数组
2、通过数组字面量创建(常用)
//1、使用数组字面量创建空数组 var 数组名 = [] //2、使用数组字面量创建带初始值的数组 var 数组名 = [元素1,元素2,元素3···] 如:var arr = [1,3,5,'a','c','e',7,9]//数组元素可以是任意数据类型的
小结:
1.数组是一组数据的集合,是将一组数据存放在同一变量的优雅方式
2.数组的字面量:[ ]
3.声明数组并赋值称为数组的初始化
4.数组中元素可以是任意类型的数据
5.注意:数组元素为字符或字符串要加引号,不加的话解释器会认为是变量从而报错
索引(下标):用来存放数组元素的序号(数组下标从0开始)
我们可以通过索引来访问、设置、修改相应的元素,注意:数组的长度可以不指定,它可以随元素的增加自动扩容,当访问未赋值的元素时,返回undefined。获取方式: 数组名[索引号]
下面通过例子来演示一下:
//定义数组 var arr = [1,3,5,'a','b','c']---->//注意字符串要加引号,不然解释器会认为是变量而报错 console.log(arr)---------------->Array(6)//输出数组长度 console.log(arr[0])------------->1 console.log(arr[2])------------->5 console.log(arr[4])------------->b
console.log(arr[6])---------- -->undefined//索引下标6没有元素,所以返回undefined 注意:数组的下标从0开始哟!!!
请看下面代码:
var arr = ["red","blue","green"] console.log(arr[0]) console.log(arr[1]) console.log(arr[2]) //输出结果:red blue green
从上面代码观察发现,取出每一个元素只是数组下标改变而已,如果数组元素多的话,一行一行访问速度很慢,为提高效率,我们可以用循环
//1、使用for循环遍历 var arr = ["red","blue","green"] for(var i = 0;i<arr.length;i++){//length是数组的属性,即为数组长度,没有() console.log(arr[i]) } //输出结果:red blue green
//2、使用for in循环遍历 var arr = ["red","blue","green"] for(var i in arr){ console.log(arr[i]) } //输出结果:red blue green
以上访问数组元素的结果是一样的,使用循环可是很便利的
下面做两个小案例来演示下数组的魔力吧!
案例1
使用数组对一组数求和并求平均值,思路:定义2个变量,一个存总和,一个存平均数,通过遍历数组求和,然后除以数组长度求平均数
案例1实现代码 //使用数组对一组数求和并求平均值 var arr = [1,3,5,7,9,2,4,6,8] //声明一个数组并初始化 var sum = 0; //创建一个变量来存取各数字之和 var avg = 0; //创建一个变量来存取平均数 for(i=0;i<arr.length;i++){ sum += arr[i]; //相当于 sum = sum + arr[i] } console.log("sum:"+sum) //打印sum的值,即所有数的和 avg = sum/arr.length //求平均值并赋值给avg(arr.lengt是数组的个数) console.log("avg:"+avg) //打印avg的值,即所有数的平均数 //输出结果:sum:45 avg:5(这里仅是演示,没有对结果为多位小数进行处理)
案例2
使用数组对一组数求最大值,图例思路:把数组第一个元素赋值给max,依次遍历比较,如果有元素大于max,则把此元素赋值给max,遍历后比完max即为最大值
案例2实现 //使用数组对一组数求最大值 var arr = [1,3,5,7,9,2,4,6,8] //声明一个数组并初始化 var max=arr[0]; //创建一个变量来存取最大值,把arr[0],即1赋值给max for(i=01;i<arr.length;i++){ if(arr[i]>max){ max=arr[i]//判断是否有数组元素大于max,有的话就把大于max的值赋值给max } } console.log("max:"+max) //打印max的值,即数组中最大值 //输出结果:max:9
// 注意!length是属性,不是函数,所以不用加() var arr = [1,2,3,4,5]; console.log(arr.length) //输出结果:5 通常数组的length属性跟数组遍历一起使用,使用循环遍历数组要注意
数组元素最后一位的索引下标是数组长度-1(arr.length-1)
// 创建数组,通过length属性扩容数组 var arr = ['a','b','c','d']; console.log(arr.length)//输出结果为4,数组长度为4 console.log(arr[3]) //输出数组最后一位元素的值为d arr.length=6; //数组长度扩容为6 console.log(arr) //输出结果为6,数组长度为6,第四第五个元素的值为empty console.log(arr[4]) //未赋值,默认为undefined console.log(arr[5]) //未赋值,默认为undefined
输出结果入图

3. 通过索引号实现数组扩容
// 创建数组,通过索引号扩容数组 var arr = ['a','b','c','d']; console.log(arr.length)//输出结果为4,数组长度为4 console.log(arr[3]) //输出数组最后一位元素的值为d arr[4]='A' //给第五个元素进行赋值,因为第5个元素没被占用,所以会在数组后面追加元素 arr[5]='B' //给第六个元素进行赋值 arr[10] = 'C' //给第11个元素进行赋值 console.log(arr) console.log(arr[6])
运行结果如图,可以发现,JS数组可以直接通过索引号进行扩容,而未赋值的元素默认为empty,返回结果是undefined,如果元素不存在,则在数组后面追加元素,若已经存在,则替换数组元素–>arr[3]
注意:不要直接给数组名赋值,否则会覆盖原有数组!
// 演示 var arr=[1,2,3,4,5] console.log(arr)//打印原数组 arr="有点意思!" console.log(arr)
1. shift()删除数组中的第一个元素并且返回被删除的元素,
同时其他元素的索引向前移动一位
var fruits = ['banana', 'orange', 'apple', 'mango'] console.log(fruits) //打印原数组 var x = fruits.shift(); //首元素删除 console.log(fruits) //删除后的数组,数组元素向前索引移动一位 console.log(x) //打印被删除元素的值banana
结果如图:
2. pop()删除数组中的最后一个元素并且返回被删除的元素
var fruits = ['banana', 'orange', 'apple', 'mango'] console.log(fruits) //打印原数组 var x = fruits.pop(); //末尾元素删除 console.log(fruits) //删除后的数组 console.log(x) //打印被删除元素的值mango
结果如图:
3. unshift(参数1,参数2···)向数组的开头添加一个或者更多的元素并且返回新的长度,
同时数组元素的索引向后移动
var fruits = ['orange', 'apple', 'mango'] console.log(fruits) //打印原数组 var x = fruits.unshift('banana'); //添加后返回数组长度 console.log(fruits) //添加后的数组 console.log(x) //打印新数组的总长度
结果如图:
4. push()向数组末尾增添一个或者多个数组元素,并且返回数组的长度
var fruits = ['orange', 'apple', 'mango'] console.log(fruits) //打印原数组 var x = fruits.push('banana'); //添加一个数后返回数组长度 console.log(fruits) //添加一个元素后的数组 console.log(x) //打印添加一个数后新数组的总长度 var x = fruits.push('pineapple','strawberry');//添加多个元素后返回数组长度 console.log(fruits) //添加多个元素后的数组 console.log(x) //添加多个元素后的总长度
结果如图
5. reverse()翻转数组
var fruits = ['orange', 'apple', 'mango'] console.log(fruits); //打印原数组 console.log(fruits.reverse()) //打印翻转后的数组
结果如图:

6. sort()数组排序,对字符串排序,比较的是ASCII码的顺序
1>如["a", "A", "1"], 按ASCII码顺序排列后为["1", "A", "a"](数字>大写字母>小写字母)
2>如["ab", "ac", "abc"], 排序后为["ab", "abc", "ac"]
3>字符串数字:如["10", "5", "18" , "50"], 排序后为["10", "18", "5", "50"]
比较方法:
(第一位相同比较第二位,b>c,因此ab和abc在ac之前;再比较ab与abc, ab没有第三位,因此排在abc之前)!!!
如需要对字符串形式的数字进行排序,可以采用以下两种方式:
1、统一格式,补足位数,如["10", "5", "18" , "50"]中, 将"5"写为"05"
2、转换为数字,使用特殊方法对数字排序
var arr1 = ["a", "A", "1"] var arr2 = ["ab", "ac", "abc"] var arr3 = ["10", "5", "18", "50"] var arr4 = ["10", "05", "18", "50"] console.log(arr1.sort()); console.log(arr2.sort()); //比较方法:按ASCII码比较排序 console.log(arr3.sort()); console.log("数字排序(5改成'05'):" + arr4.sort());
结果如图:
1、匿名函数当做参数使用数组排序(一维数组)
//语法格式:
arr.sort ( function (a, b) { //arr为需要排序的数组名
return a - b //升序
})
根据比较函数返回值正负来决定排列顺序,为正升序,为负降序
使用如下:
function sortby(a, b) { return a - b //升序 } //降序就改成return b-a var arr = [10, 5, 8, 50]; arr.sort(sortby)//把排序匿名函数当做参数进行调用 console.log(arr);//输出排序后的结果 //匿名函数的函数名任意 结果如图:
2、匿名函数当做参数使用数组排序(二维数组)
//语法格式:
arr.sort (function (a, b) { //arr为需要排序的数组名
return a[1] - b [1] //升序,降序改为b[1]-a[1]
})
使用如下:
function sortby(a, b) { return a[1] - b[1] //升序 } //降序就改成return b-a var arr = [["Alice", "95"], ["Bob", "80"], ["Cart", "100"]] arr.sort(sortby)//把排序匿名函数当做参数进行调用 console.log(arr);//输出排序后的结果 //匿名函数的函数名任意 结果如图:
将数组[2,4,5,6,8,9,12,15,3,7,26,14]中大于10的元素存入新数组
//分析:
1、创建一个数组arr=[2,4,5,6,8,9,12,15,3,7,26,14]
2、创建一个新数组newArr来存放大于10的元素
3、遍历旧数组,找出大于10的元素
4、依次添加到新数组中
// 方法1,通过变量来增加数组长度 var arr = [2,4,5,6,8,9,12,15,3,7,26,14] //创建一个数组 var newArr=[] //创建空的新数组,用于存放大于10的元素 var j =0 ; //定义变量,用于增加新数组的长度 for(var i = 0 ;i<arr.length;i++){ //for循环遍历数组 if(arr[i]>10){ //判断数组元素是否大于10 newArr[j]=arr[i] //如果arr数组元素>10,则存入新数组 j++; //当存入元素,长度+1,即j++ } } console.log(newArr)//打印新数组
// 方法2,巧用length属性 var arr = [2,4,5,6,8,9,12,15,3,7,26,14] //创建一个数组 var newArr=[] //创建空的新数组,用于存放大于10的元素 for(var i = 0 ;i<arr.length;i++){ //for循环遍历数组 if(arr[i]>10){ //判断数组元素是否大于10 newArr[newArr.length]=arr[i]//如果arr数组元素>10,则存入新数组 } //巧用length属性,数组索引从0开始增加 } console.log(newArr)//打印新数组
结果如图:
概念:二维数组就是一维数组的每个元素是一个一维数组
// 创建与访问
var fruits = [["1", "Banana"], ["2", "Orange"]];//创建二维数组 var element = ["3", "Apple"]; fruits[2] = element; //给第三个元素赋值 console.log(fruits); //打印二维数组 console.log(fruits[0]); // ["1", "Banana"]//打印第一个元素(数组) console.log(fruits[0][1]); // "Banana" //打印第一个元素的第2个值
结果如图:
通过for in循环遍历二维数组
var fruits = [["1", "Banana"], ["2", "Orange"], ["3", "Apple"]]; for (var i in fruits) {//控制外层数组元素 for (var j in fruits[i]) {//控制内层数组元素 console.log(fruits[i][j]);//输出数值中每一个元素 } }
结果如图:

小结:二维数组跟一维数组使用差不多,只是稍微麻烦一点,访问二维数组的具体元素值:arr[外层数组索引][内层数组索引]
遍历二维数组使用双重for循环
图例解释:
//代码实现如下 var arr = [5,4,3,2,1]; for (var i = 0; i < arr.length - 1; i++) {//外层循环控制交换趟数,趟数为数组长度-1 for (var j = 0; j < arr.length - 1 - i; j++) {//内层循环控制每一趟需要交换的次数 if (arr[j] > arr[j + 1]) {//判断前面一个数是否大于后面一个数,如果是则交换两数 var temp = arr[j];//临时变量,用于交换两数的临时存取 arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } console.log(arr);//输出排序后的结果
结果如图:
本次笔记主要记录了数组的基本使用,但是数组的妙用远不止这些,需要我们自己去探索。
转自:csdn论坛 作者:想要搞钱
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
蓝蓝设计的小编 http://www.lanlanwork.com