首页

Ajax是什么?Ajax高级用法之Axios技术

前端达人

AJAX

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

关键字:异步、回调、局部刷新。

异步请求局部刷新

主流方式:
在这里插入图片描述
技术栈

  • HTML 页面展示
  • JavaScript 形成交互
  • jQuery 封装JavaScript,代码更加简洁高效
  • json 数据传输
  • ajax 异步请求
  • Web中间件(tomcat) 处理请求和响应
  • mysql数据库 存取数据

用户页面中触发ajax请求,访问后端服务器,Web 中间件 拦截用户请求,转发后端程序进行数据处理,一般还需访问数据库,然后逐层返回。数据库返回数据处理服务,数据处理服务返回Web中间件,Web中间件返回ajax调用,将数据封装到返回的js对象中,目前主流返回数据为json字符串(可以通过Jsonp格式实现跨域访问)。在回调callback的方法中解析json中的数据,最终回显到页面上。通常我们使用jquery封装过的ajax,写法更加简洁灵活。

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);    //错误信息
    }
}) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

js、json、jsonp区别

json和jsonp的区别

json请求返回就是json格式,而jsonp请求返回是fun(json)格式。

  • 京东的价格是单独发起ajax请求,返回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"}] 
  • 1
  • 2
  • 京东的商品描述是单独发起ajax请求,返回jsonp格式数据,回显到页面

查询网址:https://d.3.cn/desc/1411000

通过JSONView插件展示数据:
在这里插入图片描述
网站有一个跨域问题,非同一个网站的请求默认是禁止的**(同源策略)**,那我们的页面要访问其他网站啊,例如:我们访问京东获取其商品的价格信息。这时就必须用jsonp方式进行跨域请求。

同源策略

同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。

json和js对象的区别

json字符串:   { "id":"100","name":"tony","salary":"30000" }
js对象:       { "id":100,"name":"tony","salary":30000 } 
  • 1
  • 2

可以看出js对象中value值如果是整数,小数,无需加双引号

  • 含义不同,json是一种数据格式,js对象表示类的实例
  • 传输:json用于跨平台、跨网络传输,速度快;js不能传输
  • 展现:json是字符串不能是对象方法函数;js值不一定加双引号,值可以是对象、函数、字符串等
  • 转换:JSON已经作为浏览器内置对象,eval(json)、JSON.parse(jsonStr) 、JSON.stringify(obj)

Ajax高级用法(axios)

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> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

注意:
axios请求头的 Content-Type 默认是 application/json,而postman默认的是 application/x-www-form-urlencoded。

ajax一般采用@RequestParam接收参数:

@ResponseBody public Result testpost(@RequestParam String username) {} 
  • 1
  • 2

axiso采用@RequestBody的json方式接收参数

@ResponseBody public Result testget(@RequestBody Map map) {} 
  • 1
  • 2

为什么要用Axios

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

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

  • 本身是针对MVC的编程,不符合现在前端MVVM的浪潮
  • 基于原生的XHR开发,XHR本身的架构不清晰。
  • JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)
  • 不符合关注分离(Separation of Concerns)的原则
  • 配置和调用方式非常混乱,而且基于事件的异步模型不友好。

Vue2.0之后,尤雨溪推荐大家用axios替换JQuery ajax,想必让axios进入了很多人的目光中。

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

  • 从浏览器中创建 XMLHttpRequest
  • 支持 Promise API
  • 客户端支持防止CSRF
  • 提供了一些并发请求的接口(重要,方便了很多的操作)
  • 从 node.js 创建 http 请求
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据

防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key,根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。

fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多了,参数有点像jQuery ajax。但是,一定记住fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。

总得来说:axios既提供了并发的封装,也没有fetch的各种问题,而且体积也较小,当之无愧现在最应该选用的请求的方式。


转自:csdn 论坛 作者:布诺i

vue 前端解决跨域问题 —代理

前端达人

前言
跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号(如存在)相同,则允许相互访问。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源,主要是安全问题。

在很多时候跨域问题我都是让后端解决,嘿嘿。但也有需要自己解决的项目!

  1. 首先在项目的根目录下建一个vue.config.js

  2. 如下:

  3. //改变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界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服


IDEA2021 tomcat10 servlet 较新版本 踩坑记录

前端达人

因为学习的时候用的版本比较新,而网上的教程又全是老版本,所以出现了很多问题,总结以下,帮同样初学的师傅们踩坑了。
废话不多说:

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(); } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

然后修改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界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服

死磕javascript的手写面试题

前端达人

1.实现lodash的_.get方法

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
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
测试:
let obj = {
  a:{
    b:[
      {
        c:2
      }
    ]
  }
}

console.log(_getValue(obj, 'a.b[0].c')) //2 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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'
  }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
测试:
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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3.数组扁平化的方法

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;
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
let arr = [1,2,[3,4,[5,6]]]
_flat(arr) //[1,2,3,4,5,6] 
  • 1
  • 2
//es6
function _flat2(arr){
  while(arr.some(item=>Array.isArray(item))){
    arr = [].concat(...arr)
  }
  return arr
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
let arr = [1,2,[3,4,[5,6]]]
_flat2(arr) //[1,2,3,4,5,6] 
  • 1
  • 2

4.深克隆

简单深克隆,不考虑内置对象和函数

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
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

复杂版深度克隆 考虑内置对象 比如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;
    }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

5.数组去重

filter去重

function _unique(arr){
  return arr.filter((item,index,array)=>{
    return array.indexOf(item) === index
  })
} 
  • 1
  • 2
  • 3
  • 4
  • 5

es6 Set

function _unique2(arr){
  return [...new Set(arr)]
} 
  • 1
  • 2
  • 3

includes

function _unique3(arr){
  let newArr = []
  arr.forEach(item => {
      if(!newArr.includes(item)){
        newArr.push(item)
      }
  });
  return newArr
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

双层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
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

6.判断数据的类型

function _typeOf(obj){
  let res = Object.prototype.toString.call(obj).split(' ')[1]
  let mold = res.substring(0,res.length-1).toLowerCase()
  return mold
} 
  • 1
  • 2
  • 3
  • 4
  • 5
_typeOf(5) //number
_typeOf('5') //string 
  • 1
  • 2

7.解析url参数为对象

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
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

8.函数柯里化

//从一次传入多个参数  编程多次调用每次传入一个参数
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) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

9.图片懒加载

//添加了两个功能
// 图片加载完成后 移除事件监听
// 加载完的图片从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) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

图片懒加载:https://juejin.cn/post/6844903856489365518#heading-19

10节流防抖

函数防抖 触发高频事件 事件在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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
// 复杂版
// 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)``` 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

函数节流 触发高频事件 且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
    }
  }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
//定时器
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)
    }
  }

} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
//组合版 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欧

Vue双向数据绑定原理

前端达人

1. vue双向数据绑定是通过 数据劫持,并结合 发布-订阅模式的方法来实现的,也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变

2. 核心:关于vue实现双向数据绑定,其核心是Object.defineProperty()方法

3. 介绍一下Object.defineProperty()方法

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' 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4. 再介绍一下发布-订阅模式

在这里插入图片描述

原文来自于这里,我说一下我自己的理解,其实发布-订阅模式和观察者模式很像,但是不同的是,观察者模式只有两个角色,而且Obsever是知道Subject的,但是在发布-订阅模式中,他们两却彼此不了解,他们是在一种类似于中间件的帮助下进行通信的,换句话说,还有第三个组件,称为代理或消息代理或事件总线,Observer和Subject都知道该组件,该组件过滤所有传入消息并相应的分发他们。

5. 然后就是简单模拟实现一下Vue的双向数据绑定

<input type="text"> <p></p> 
  • 1
  • 2

我们要对上面两个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> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

所以在我们的代码中,订阅者就是页面中的DOM元素,因为他会订阅我们的inputvalue,而发布者就是监听事件中的数据,一旦监听到了数据有修改,就要发布给我们的订阅者,也就是说输入的数据一旦发生了变化,我们的页面DOM元素的数据也会发生变化,所以这个中间件就是Object.defineProperty中的set方法

6. 结果演示

在这里插入图片描述


转自:csdn 论坛 作者:Y shǔ shǔ


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服

JavaScript学习(三十八)—面向过程与面向对象

前端达人

JavaScript学习(三十八)—面向过程与面向对象

一、程序设计语言中的两大编程思想:面向对象、面向过程

(一)、面向过程

  • 就是指完成某个需求的时候,先分析出完成该需求时所需要经历的步骤有哪些,然后按照步骤依次执行,最终实现我们想要的效果。这种编程思想就是面向过程,典型的面向过程的编程语言有C语言。

(二)、面向对象

  • 就是在完成某个需求的时候,先分析完成该需求所需要涉及的对象有哪些,然后找出这些对象所具有的属性和方法,利用这些属性和方法帮助我们完成需求。这种编程思想就是面向对象。典型的面向对象的语言有Java、C++。

在这里插入图片描述

(三)、什么是对象?

  • 所谓的对象就是指具有特定功能的无序的属性的集合。JS中的对象有内置对象,也可以根据需求自定义对象。

自定义对象的方式主要有以下几种:
字面量形式、工厂形式、构造方法

(四)、字面量形式的创建
格式:

var 对象名称={ 属性名称1:属性,1,

    属性名称2:属性值2,

    属性名称3:属性值3,

    属性名称n:属性值n, }; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

沙场练兵:

<!-- 创建一个汽车对象 1、属性:品牌、价格、颜色等、 2、方法(功能):跑、停 --> <body> <script> var car = { brand: '宝马', price: '100万', color: 'red', run: function() { console.log('汽车跑起来了'); }, stop: function() { console.log('汽车停下来了'); } }; console.log(car); </script> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在这里插入图片描述

 <script> var person = { name: '小王', age: '18', gender: '女', eat: function() { console.log('方便面'); }, play: function() { console.log('王者荣耀'); }, study: function() { console.log('web前端'); } }; console.log(person); </script> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述

转自:csdn论坛 作者:乘风破浪的程序媛


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服

JavaScript操作符in:由一个问题引发的探究

前端达人

事情是这样的:大家都知道“内存泄露”这回事吧。它有几个常见的场景:

  1. 闭包使用不当引起内存泄漏
  2. (未声明的)全局变量
  3. 分离的DOM节点
  4. (随意的)控制台的打印
  5. 遗忘的定时器
  6. 循环引用

内存泄漏需要重视,它是如此严重甚至会导致页面卡顿,影响用户体验!

其中第 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> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

该代码所做的操作就是点击按钮后移除.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> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这段代码很完美么?不。因为它在每次事件触发后都创建了对child和root节点的引用。消耗了内存(你完全可以想象一些人会狂点按钮的情况…)。
其实还有一种办法:我们在click中去判断当前root节点中是否还存在child子节点,如果存在,则执行remove函数,否则什么也不做!

这就引发了标题中所说的行为。

怎么判断?
遍历?不,太过麻烦!
不知怎的,我突然想到了 for...in 中的 in 操作符,它可以基于原型链遍历对象!

我们来还原一下当时的场景:打开GitHub,随便找一个父节点,并获取它:
mygithub
图中画红框的就是我们要取的父元素,橘红色框的就是要判断是否存在的子元素。

let parent=document.querySelector('.position-relative'); let child=document.querySelector('.progress-pjax-loader'); 
  • 1
  • 2

这里注意,因为获取到的是DOM节点(类数组对象),所以我们在操作前一定要先处理一下:
object

let p_child=[...parent.children]; 
  • 1

array
然后

console.log(child in p_child); 
  • 1

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

console.log(p_child.includes(child)); 
  • 1

yes
没错啊!
再用一般的数组验证一下:
Verification
???
此时,笔者才想起到MDN上查阅一番:
mdn
进而我发现:in操作符单独使用时它检测的是左侧的值(作为索引)对应的值是否在右侧的对象内部(属性 & 原型上)

回到上面的代码中,我们发现:
vertification_2
这验证了我们的结论。
很显然,“子元素”并不等同于“存在于原型链上” —— 这又引出了一个知识点: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> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17



















转自:csdn论坛   作者:恪愚


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服



JavaScript逐点突破系列之this是什么?了解完这7点很多疑惑都解决

前端达人

前言

本章将专门介绍与执行上下文创建阶段直接相关的最后一个细节——this是什么?以及它的指向到底是什么。

了解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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

what?怎么people2变性了呢,这不是我想要的结果啊,为什么呢?

因为getGender()返回(return)写死了people1.gender的关系,结果自然是’female’。

那么,如果我们把getGender稍改一下:

var getGender = function() {
    return this.gender;
}; 
  • 1
  • 2
  • 3
  • 4

这个时候,你应该会分别得到femalemale两种结果。

所以回到前面讲的重点,从这个例子可以看出,即便people1people2getGender方法参照的都是同一个getGender function,但由于调用的对象不同,所以执行的结果也会不同

现在我们知道了第一个重点,**this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数的调用方式。**如何的区分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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果普通函数是在全局环境中被调用,在非严格模式下,普通函数中 this 也指向全局对象;如果是在严格模式下,this 将会是 undefined。ES5 为了使 JavaScript 运行在更有限制性的环境而添加了严格模式,严格模式为了消除安全隐患,禁止了 this 关键字指向全局对象。

var x = 1

function fn() {
    console.log(this);   // Window 全局对象
    console.log(this.x);  // 1
}

fn(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

使用严格模式后:

"use strict"     // 使用严格模式
var x = 1

function fn() {
    console.log(this);   // undefined
    console.log(this.x);  // 报错 "Cannot read property 'x' of undefined",因为此时 this 是 undefined
}

fn(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

情况二:作为对象方法的调用

我们知道,在对象里的值如果是原生值(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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在上面的例子中,直接运行 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(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

为什么结果不是 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(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

对象可以嵌套,函数也可以,如果函数嵌套,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(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在函数 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(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

情况三:作为构造函数调用

我们可以使用 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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

使用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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

因为Fn()返回(return)的是一个对象(引用类型),this 会指向这个return的对象。如果return的是一个非引用类型的值呢?

var x = 1

function Fn() {
  this.x = 2

  return 3
}

var a = new Fn()

console.log(a.x)      // 2 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

情况四: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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

使用 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] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

情况五: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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

在上面的例子中,虽然我们尝试给函数 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 ownthis,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() 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

和普通函数不一样,箭头函数中的 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() 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

上例中,虽然存在两个箭头函数,其实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 全局对象 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

上面的文字描述过多可能有点干涩,那么就看以下的这张流程图吧,我觉得这个图总结的很好,图中的流程只针对于单个规则。

小结

本篇文章介绍了 this 指向的几种情况,不同的运行环境和调用方式都会对 this 产生影响。总的来说,函数 this 的指向取决于当前调用该函数的对象,也就是执行时的对象。在这一节中,你需要掌握:

  • this 指向全局对象的情况;
  • 严格模式和非严格模式下 this 的区别;
  • 函数作为对象的方法调用时 this 指向的几种情况;
  • 作为构造函数时 this 的指向,以及是否 return 的区别;
  • 使用 call 和 apply 改变调用函数的对象;
  • bind 创建的函数中 this 的指向;

  • 箭头函数中的 this 指向。
  • 转自:csdn 论坛  作者:蛋黄酥要不要来一口阿

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服

vue.js前端框架:Vue.js简介

前端达人

1 Vue.js概述

  • Vue.js(读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其他重量级框架不同的是,它只关注视图层(View层),采用自底向上增量开发的设计。Vue.js的目标是通过尽可能简单的API实现相应的数据绑定和组合的视图组件。它不仅容易上手,还非常容易与其他库或已有项目进行整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue .js也完全能够为复杂的单页应用提供驱动。

1.1 什么是Vue.js

  • Vue.js实际上是一个用于开发Web前端界面的库,其本身具有响应式编程和组件化的特点。所谓响应式编程,即保持状态和视图的同步。响应式编程允许将相关模型的变化自动反映到视图上,反之亦然。Vue.js采用的是MVVM(Model-View-ViewModel)的开发模式。与传统的MVC开发模式不同,MVVM将MVC中的Controller改成了ViewModel。在这种模式下,View的变化会自动更新到ViewModel,而ViewModel的变化也会自动同步到View上进行显示。
  • ViewModel模式的示意图如下图所示:
    在这里插入图片描述
  • 与ReactJS一样,Vue.js同样拥有”一切都是组件“的理念。应用组件化的特点,可以将任意封装好的代码注册成标签,这样就在很大程度上减少了重复开发,提高了开发效率和代码复用性。如果配合Vue.js的周边工具vue-loader,可以将一个组件的HTML、CSS、JavaScript代码都写在一个文件中,这样可以实现模块化的开发。

1.2 Vue.js的特性

  • Vue.js的主要特性如下:
  •  轻量级
    相比较AngularJS和ReactJS而言,Vue.js是一个更轻量级的前端库。不但容量非常小,而且没有其它的依赖。
  •  数据绑定
    Vue.js最主要的特点就是双向的数据绑定。在传统的Web项目中,将数据在视图层展示出来后,如果需要再次修改视图,需要通过获取DOM的方法进行修改,这样才能维持数据和视图的一致。而Vue.js是一个响应式的数据绑定系统,在建立绑定后,DOM将和Vue对象中的数据保持同步,这样就无须手动获取DOM的值再同步到 js中。
  •  应用指令
    同AngularJS一样,Vue.js也提供了指令这一概念。指令用于在表达式的值发生变化时,将某些行为应用到绑定的DOM上,通过对应表达式值的变化就可以修改对应的DOM。
  •  插件化开发
    与AngularJS类似,Vue,js也可以用来开发一个完整的单页应用。在Vue.js的核心库中并不包含路由、Ajax等功能,但是可以非常方便地加载对应插件来实现这样的功能。例如,vue-router插件提供了路由管理的功能,vue-resource插件提供了数据请求的功能。

2 Vue.js的安装

2.1 直接下载并使用 script 标签引入

  • Vue.js官网:https://cn.vuejs.org/v2/guide/
  • 在Vue.js的官方网站中可以直接下载vue.js文件并使用 script标签引入。
    1、下载Vue.js
    Vue.js是一个开源的库,可以从它的官方网站中下载。下面介绍具体的下载步骤:
    (1)打开Vue.js的官方网站,进入到Vue.js的下载页面,找到如下图1.2所示的内容。
    在这里插入图片描述
    (2)根据开发者的实际情况选择不同的版本进行下载。这里以下载开发版本为例,在”开发版本“按钮上单击鼠标右键,如下图1.3所示。
    在这里插入图片描述
    (3)在弹出的快捷菜单中单击“连接另存为”选项,弹出下载对话框,如下图1.4所示,单击对话框中的“保存”按钮,将Vue.js文件下载到本地计算机上。在这里插入图片描述此时下载的文件为完整不压缩的开发版本。如果在开发环境下,推荐使用该版本,因为该版本中包含所有常见错误相关的警告。如果在生产环境下,推荐使用压缩后的生产版本,因为使用生产版本可以带来比开发环境下更快的速度体验。
  • 引入Vue.js
    将Vue.js下载到本地计算机后,还需要在项目中引用Vue.js。即将下载后的vue.js文件放置到项目的指定文件夹中。通常文件放置在JS文件夹中,然后在需要应用vue.js文件的页面中使用下面的语句,将其引入到文件中。
<script type="text/javascript" src="JS/vue.js"></script> 
  • 1

注意:引入Vue.js的 script 标签,必须放在所有的自定义脚本文件的script 之前,否则在自定义的脚本代码中应用步到Vue.js。

2.2 使用CDN方法

  • 在项目中使用Vue.js,还可以采用引用外部CDN文件的方式。在项目中直接通过 script 标签加载CDN文件,通过CDN文件引用Vue.js的代码如下:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.js"></script> 
  • 1

注意:为了防止出现外部CDN文件不可用的情况,还是建议用户将Vue.js下载到本地计算机中。

2.3 使用NPM方法

  • 在使用Vue.js构建大型应用时,推荐使用NPM方法进行安装,执行命令如下:
npm install vue 
  • 1

注意:使用NPM方法安装Vue.js需要在计算机中安装node.js。
node;js官网:https://nodejs.org/en/,通过node.js官网下载之后,傻瓜式安装即可。

3 前端框架开发工具

  • 利用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笔记之快乐的数组

前端达人


数组(Array)

概念:数组是一组数据的集合,其中每一个数据称为数组元素,js的数组可以放任意数据类型的元素,数组是一种将一组数据元素存储在单个变量名下的优雅方式。

示例解释:

//普通变量名只能存一个数据 var num = 10 //数组存储一组数据 var arr = [1,2,3,4,5,'a','b','c'] 
  • 1
  • 2
  • 3
  • 4

一、数组的创建

数组的创建方式:
1、通过new关键字创建(不常用)

//注意A要大写 var 数组名 = new Array() var arr = new Array()//创建一个空数组 var arr = new Array(5)//创建一个长度为5的空数组 
  • 1
  • 2
  • 3
  • 4

2、通过数组字面量创建(常用)

//1、使用数组字面量创建空数组 var 数组名 = [] //2、使用数组字面量创建带初始值的数组 var 数组名 = [元素1,元素2,元素3···] 如:var arr = [1,3,5,'a','c','e',7,9]//数组元素可以是任意数据类型的 
  • 1
  • 2
  • 3
  • 4
  • 5

小结:
1.数组是一组数据的集合,是将一组数据存放在同一变量的优雅方式
2.数组的字面量:[ ]
3.声明数组并赋值称为数组的初始化
4.数组中元素可以是任意类型的数据
5.注意:数组元素为字符或字符串要加引号,不加的话解释器会认为是变量从而报错

二、数组元素的访问

1.通过数组索引访问

索引(下标):用来存放数组元素的序号(数组下标从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开始哟!!! 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.通过循环遍历

请看下面代码:

var arr = ["red","blue","green"] console.log(arr[0]) console.log(arr[1]) console.log(arr[2]) //输出结果:red blue green 
  • 1
  • 2
  • 3
  • 4
  • 5

从上面代码观察发现,取出每一个元素只是数组下标改变而已,如果数组元素多的话,一行一行访问速度很慢,为提高效率,我们可以用循环

//1、使用for循环遍历 var arr = ["red","blue","green"] for(var i = 0;i<arr.length;i++){//length是数组的属性,即为数组长度,没有() console.log(arr[i]) } //输出结果:red blue green 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
//2、使用for in循环遍历 var arr = ["red","blue","green"] for(var i in arr){ console.log(arr[i]) } //输出结果:red blue green 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

以上访问数组元素的结果是一样的,使用循环可是很便利的
下面做两个小案例来演示下数组的魔力吧!
案例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(这里仅是演示,没有对结果为多位小数进行处理) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

案例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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

三、数组的操作

1.数组长度及数组扩容

  1. 使用length属性获取数组长度
// 注意!length是属性,不是函数,所以不用加() var arr = [1,2,3,4,5]; console.log(arr.length) //输出结果:5 通常数组的length属性跟数组遍历一起使用,使用循环遍历数组要注意
数组元素最后一位的索引下标是数组长度-1(arr.length-1) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. 使用length属性实现数组扩容
// 创建数组,通过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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出结果入图
在这里插入图片描述
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]) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运行结果如图,可以发现,JS数组可以直接通过索引号进行扩容,而未赋值的元素默认为empty,返回结果是undefined,如果元素不存在,则在数组后面追加元素,若已经存在,则替换数组元素–>arr[3]

在这里插入图片描述

注意:不要直接给数组名赋值,否则会覆盖原有数组!

// 演示 var arr=[1,2,3,4,5] console.log(arr)//打印原数组 arr="有点意思!" console.log(arr) 
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述


2.数组的常用方法

 1. shift()删除数组中的第一个元素并且返回被删除的元素,
    同时其他元素的索引向前移动一位 
  • 1
  • 2
var fruits = ['banana', 'orange', 'apple', 'mango'] console.log(fruits) //打印原数组 var x = fruits.shift(); //首元素删除 console.log(fruits) //删除后的数组,数组元素向前索引移动一位 console.log(x) //打印被删除元素的值banana 
  • 1
  • 2
  • 3
  • 4
  • 5

结果如图:
在这里插入图片描述

 2. pop()删除数组中的最后一个元素并且返回被删除的元素 
  • 1
var fruits = ['banana', 'orange', 'apple', 'mango'] console.log(fruits) //打印原数组 var x = fruits.pop(); //末尾元素删除 console.log(fruits) //删除后的数组 console.log(x) //打印被删除元素的值mango 
  • 1
  • 2
  • 3
  • 4
  • 5

结果如图:
在这里插入图片描述

 3. unshift(参数1,参数2···)向数组的开头添加一个或者更多的元素并且返回新的长度,
    同时数组元素的索引向后移动 
  • 1
  • 2
var fruits = ['orange', 'apple', 'mango'] console.log(fruits) //打印原数组 var x = fruits.unshift('banana'); //添加后返回数组长度 console.log(fruits) //添加后的数组 console.log(x) //打印新数组的总长度 
  • 1
  • 2
  • 3
  • 4
  • 5

结果如图:
在这里插入图片描述

 4. push()向数组末尾增添一个或者多个数组元素,并且返回数组的长度 
  • 1
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) //添加多个元素后的总长度 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

结果如图
在这里插入图片描述

 5. reverse()翻转数组 
  • 1
 var fruits = ['orange', 'apple', 'mango'] console.log(fruits); //打印原数组 console.log(fruits.reverse()) //打印翻转后的数组 
  • 1
  • 2
  • 3

结果如图:
在这里插入图片描述
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、转换为数字,使用特殊方法对数字排序 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

结果如图:
在这里插入图片描述

3.拓展:数字排序

1、匿名函数当做参数使用数组排序(一维数组)

//语法格式:
arr.sort ( function (a, b) {   //arr为需要排序的数组名
    return a - b               //升序
})  
根据比较函数返回值正负来决定排列顺序,为正升序,为负降序
使用如下: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
 function sortby(a, b) { return a - b //升序 } //降序就改成return b-a var arr = [10, 5, 8, 50]; arr.sort(sortby)//把排序匿名函数当做参数进行调用 console.log(arr);//输出排序后的结果 //匿名函数的函数名任意 结果如图: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

2、匿名函数当做参数使用数组排序(二维数组)

//语法格式:
arr.sort (function (a, b) {   //arr为需要排序的数组名
    return a[1] - b [1]      //升序,降序改为b[1]-a[1]
})  
使用如下: 
  • 1
  • 2
  • 3
  • 4
  • 5
 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);//输出排序后的结果 //匿名函数的函数名任意 结果如图: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

3.拓展:数组筛选(巧用length属性)

将数组[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
  • 2
  • 3
  • 4
  • 5
  • 6
// 方法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)//打印新数组 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
// 方法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)//打印新数组 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

结果如图:
在这里插入图片描述

四、二维数组

概念:二维数组就是一维数组的每个元素是一个一维数组

1.二维数组的创建与访问

// 创建与访问 
  • 1
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个值 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

结果如图:
在这里插入图片描述

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]);//输出数值中每一个元素 } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

结果如图:
在这里插入图片描述
小结:二维数组跟一维数组使用差不多,只是稍微麻烦一点,访问二维数组的具体元素值:arr[外层数组索引][内层数组索引]
遍历二维数组使用双重for循环

3.使用二维数组进行排序(冒泡排序法)

图例解释:
在这里插入图片描述

//代码实现如下 var arr = [5,43,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);//输出排序后的结果 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

结果如图:
在这里插入图片描述

总结

本次笔记主要记录了数组的基本使用,但是数组的妙用远不止这些,需要我们自己去探索。


转自:csdn论坛 作者:想要搞钱

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服


日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档