Skip to content
jiang2016tao edited this page Aug 16, 2019 · 49 revisions

js编码问题

encodeURIComponent使用:http://www.w3school.com.cn/jsref/jsref_encodeURIComponent.asp
decodeURIComponent使用:http://www.w3school.com.cn/jsref/jsref_decodeURIComponent.asp
js面向对象之公有、私有、静态属性和方法详解:http://www.jb51.net/article/64278.htm
js中call()和apply()方法用法总结 参考:http://blog.csdn.net/ganyingxie123456/article/details/70855586

js复制

在项目中有时候我们需要在某个地方,对一些文本进行复制的操作。js提供document.execCommand("copy")在浏览器执行复制命令,但是在执行命令前必须要对文本进行选中,可以用select()方法。注意select()方法只对

<input type="text"/>

和<textarea></textarea>这两个标签有效。

$(e.target).closest("div").find("input")[0].select();
            document.execCommand("copy");

通常复制的内容是我们不想展示的,这个时候input和textarea不能设置隐藏,或者改变高度和宽度为0,这些都会影响功能。只能将其设为透明的,不想占用位置,可以设置position:ablute。(这是在项目中遇到的解决方法)

ES6

const {
  state = {}, //rootState
  plugins = [], // 插件
  strict = false //是否严格模式
   } = options

上面的js语法分析,说白了其实就是一个赋值的逻辑。在options对象中如果存在属性state的对象,那么state就是被覆盖,取后面的数据;反之如果没有那么就是前面大括号里的默认值了。其实这就是一次性定义了多个变量。这就是所谓的结构解析。

结构解析

结构解析:从数组和对象中提取值对变量进行赋值。变量和赋值的值是一一对应的。

<script>
    let [a,b]=[1,2];
    console.log(a);//1
    console.log(b);//2

    let {c=1,d=2}={c:3,d:4};
    console.log(c);//3
    console.log(d);//4

    //一一对应
    let [,,g]=[5,6,7];
    console.log(g);//7

    //这里...i会将后面的所有值当数组一样赋值给i
    let [h,...i]=[8,9,10,11];
    console.log(h);//8
    console.log(i);//9,10,11
</script>

在结构解析时,给变量赋值默认值,如果在右侧的数组和对象中有值,就会被重新赋值,否则使用默认值。但是undefined不会覆盖默认值。

//默认赋值
    let [j="jiang",k,l="test"]=[,12,undefined];
    console.log(j);//jiang
    console.log(k);//12
    console.log(l);//test

在数组解析中都是数组,可迭代的。
只要某种数据结构具有Iterator接口,都可以采用数组形式的解构赋值。
下面例子参考:高阶函数generator

let [m,n,o]=new Set([13,14,15]);
    console.log(m);
    console.log(n);
    console.log(o);
    //generator(生成器)是ES6标准引入的新的数据类型.可以返回多次,[高阶函数generator](https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143450083887673122b45a4414333ac366c3c935125e7000)
    function* fibs() {
        let a=0;
        let b=1;
        while (true){
            yield a;//这句是返回的值
            [a,b]=[b,a+b];
        }
    }
    let [p,q,w]=fibs();
    console.log(w);

对象解构:对象解构是不需要一一对应的。

let {name,age}={age:28,name:"jiang"};
    console.log(name);
    console.log(age);

当变量与对象的属性名不一致时:

 let {name:person_name,age:person_age}={age:28,name:"jiang"};
    console.log(person_name);

默认值,这与数组类似。只有对象属性为undefined的,才不会赋值默认值,其他的都会。

let {x=3,y=4}={x:undefined,y:null};
    console.log(x);//3
    console.log(y);//null

当变量与对象的属性名不一致时,赋值:

let {message:msg="hello world"}={};
    console.log(msg);

对象现有方法的赋值类似对象属性赋值变量。
字符串的解构赋值:类似将字符串分割成数组了。

let [a,b,c]="ABC";
    console.log(a);
    console.log(b);
    console.log(c);

字符串属性的解构:类似将字符串当做对象了。

let {length}="ABCD";
    console.log(length);

函数参数的解构:

function test([x,y]){
        return x+y;
    }
    console.log(test([2,3]));

函数参数带默认值:

function test2({x=1,y=0}={}) {
        return x+y;
    }
    console.log(test2());
    console.log(test2({x:4}));
    console.log(test2({y:4}))

下面是函数参数带默认值的错误实例:

function test3({x,y}={x:2,y:3}){
        return x+y;
    }
    console.log(test3());

解构的用途

交换变量的值

var a=100;
    var b=100;
    var temp=a;
    a=b;
    b=a;

上面的代码是ES5,目的是交换a和b的值。那么下面用ES6来写。

let x=100;
    let y=200;
    [x,y]=[y,x];
    console.log(x);
    console.log(y);

看看,只用[x,y]=[y,x];就解决了,是不是更简洁。

从函数返回多个值

无非就是函数返回对象或数组,在将对象或数组解构给变量。

函数参数的定义

1.参数是有序的。采用数组,在解构给变量。

function test([x,y]){}

2.参数是无序的。采用对象,再解构给变量。

function test2({x,y}){}

当然,可以将数组和对象封装好了传给函数。

提取JSon数据

通过解构将一个大的json对象拆分为多个变量或对象。

函数参数的默认值

遍历Map

<script>
    let map=new Map();
    map.set("id","12");
    map.set("name","jiang");
    //注意是数组,不要使用对象了
    for(let [key,value] of map){
        console.log(key);
        console.log(value);
    }
    for(let [key] of map){
        console.log(key);
    }
    for(let [,value] of map){
        console.log(value);
    }
</script>

输入模块的引入

就是指定引入模块的部分方法等。
其实这些都是使用了,目前的对象解构和数组解构的。
在js文件中,到处模块,如果要到处多个使用export ,使用export default默认是一个文件只导出一个。
ES6规定:var和function声明的全局变量是全局对象的属性;let、const和class声明的全局变量不是全局对象的属性。举个例子:

<script>
    var temp="test";
    console.log(window.temp);
    function testFun(){};
    console.log(window.testFun);

    let temp1="test";
    console.log(window.temp1);
    const temp2="temp2";
    console.log(window.temp2);

</script>

如上面代码后面两个都是undefined,可见在浏览器的全局变量window里没有那两个属性。在nodejs中全局变量是gload。

移动端触屏触发事件

https://www.cnblogs.com/susanws/p/5717811.html

触发屏幕和点击事件依次的顺序:touchstart,touchmove,touchend,click

让软键盘出现search按钮的使用方式

<form @keydown.enter="searchGraph()">
                            <input type="search" class="search-input" :style="'width:'+inputSearchWidth" placeholder="图形名称 / 指标ID" v-model="searchText" @focus="searchInputFocus()" @blur="searchInputBlur()"/>
                            <i class="wbk-ground-img-Search_Dft" @click="searchGraph()"></i>
                        </form>

将input的type设置为search,并且要放在form标签里面。

移动端页面 滚动结束 判断

参考https://www.cnblogs.com/zldream1106/p/mobile_scroll_end.html

数据的双向绑定

用了一些双向数据的绑定,但是没有仔细研究那些框架是如何做到进行双向绑定的。今天来学习一下如何用js简单的做双向绑定,希望对以后的学习有帮助。JavaScript实现一个双向数据绑定
通过Object.defineProperty来定义新属性或修改原有的属性。其语法如下:

Object.defineProperty(obj, prop, descriptor)

语法中,obj是需要操作的目标对象,prop是需要定义或修改的属性名字,descriptor所拥有的特性。然而,关于descriptor目前有两种形式:数据描述和存取器描述。关于存取器描述,它允许我们定义get,set等其它属性。
具体如何应用,我给大家举一个例子:

<body>
    <div id="app">
        <input type="text" id="text"/>
        <p id="show_text"></p>
    </div>
</body>
<script>
    let obj={};
    let inputDom=document.getElementById("text");
    let showDom=document.getElementById("show_text");
    Object.defineProperty(obj,"txt",{
        get:function () {
            return obj;
        },
        set:function (value) {
            showDom.innerText=value;
        }
    });
    inputDom.addEventListener("keyup",function(e){
        obj.txt=e.target.value;
    })
</script>

数组去重

在项目中,往往需要对数组进行去重处理。js的一些技巧

const removeDuplicateItems = arr => [...new Set(arr)];
removeDuplicateItems([42, 'foo', 42, 'foo', true, true]);
//=> [42, "foo", true]

数组排序

js中用方法sort()为数组排序。sort()方法有一个可选参数,是用来确定元素顺序的函数。如果这个参数被省略,那么数组中的元素将按照ASCII字符顺序进行排序。
js中的数组对象排序

认识高阶函数map

["1", "2", "3"].map(parseInt) 答案是多少? [1, NaN, NaN] 因为 parseInt 需要两个参数 (val, radix),其中 radix 表示解析时用的基数。map 传了 3 个 (element, index, array),对应的 radix 不合法导致解析失败。
具体原因参考:为什么 ["1", "2", "3"].map(parseInt) 返回 [1,NaN,NaN]?
主要是理解map是如何给里面函数传参数的。

连续点击触发mouseLeave事件

<li id="ael_top_li" style="cursor: pointer;" mouseover="showAelTop" mouseleave="hideAelTop">
                            <a>
                                <i class="ale-top-i">
                                </i>
                            </a>
                            <div style="height: 12px"></div>
<div class="hidden"></div>
</li>

当鼠标移入标签里的时候,隐藏的html浮动窗体就会显示出来,里面有一些点击事件的交互,用户在连续点击时,就会发现触发了mouseleave这个事件。至于为啥会触发,目前不知道。

hideAelTop:function(e,at,o){
            console.log(e.target);
            console.log(e.relatedTarget);
            console.log(e.toElement);
            var o=e.relatedTarget || e.toElement;//解决多次点击触发mouseLeave事件
            if(!o){
                return ;
            }
            isMoveover=false;
            $(".top-div").addClass("hidden");
        },

上面是mouseleave事件的js函数,通过打印观察,连续点击时,触发的相关dom节点和鼠标移动到的当前节点都是null。按理说鼠标从当前dom节点移出,那肯定应该会有相关dom节点和鼠标当前移到的dom节点。目前使用这种方法来解决我遇到的问题。
关于relatedTarget, fromElement, toElement可以参考下面的:
relatedTarget, fromElement, toElement
HTML DOM Event 对象之(toElement、fromElement、event.srcElement、event.target)

js对对象的判断方法

  • 如何用js判断一个对象是不是Array 1.Array.isArray(obj) 调用数组的isArray方法
    2.obj instanceof Array 判断对象是否是Array的实例
    3.Object.prototype.toString.call(obj) ===‘[object Array]’

Object.prototype.toString方法会取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于[object Array]的字符串作为结果,call用来改变toString的this指向为待检测的对象

4.判断对象是否有push等数组的一些方法。(这个方法有兼容问题,但也是一个简单易用的方法)
5.obj.constructor===Array //true

  • 判断一个对象是否是函数
    console.log(Object.prototype.toString.call(obj)==='[object Function]') //true或false

ajax提交form表单

  • 自己构造一个form表单来进行提交
let form=new FormData();//这里声明一个form的表单数据
form.append("name","test");//设置参数
 let option={
                url:urlFilter.getUrl("sendImg"),
                type:"POST",
                dataType:"json",
                data:form
            };
            systemTool.tpAjaxData(option);

上面的例子就是一个ajax提交form表单的例子了。

  • 可以将页面已有的form表单进行ajax提交
let form=new FormData(document.getElementById("img_form"));

这样就可以了,其他使用与上面类似。
其实在用form处理,一般是有其他的地方需要处理,如文件的处理。将文件控件设置在form表单里,提交时,spring mvc后台对文件的处理(参考我的博客)。
注意
在文件请求的ajax中option中要加上这两项才可以正常请求,否则会有问题(经验,可以查看百度,两项配置的作用)

processData:false,
contentType:false,

js将base64转换为图片文件(自己有些疑问,我将base64转换成图片文件上传到服务器生成的文件,图片无法查看)

base64ToBlob(imgUrlData,type){
            let arr=imgUrlData.split(",");
            let mime=arr[0].match(/:(.*?);/)[1] || type;
            let bytes=window.atob(arr[1]);
            let arrayBuffer=new ArrayBuffer(bytes.length);
            let unit8Array=new Uint8Array(arrayBuffer);
            for(let i=0;i<bytes.length;i++){
                unit8Array[i]=bytes.charCodeAt[i];
            }
            return new File([arrayBuffer],"test",{
                type:mime
            });
        }

imgUrlData这是base64的字符串。match这个方法使用的少,正则表达式也不是很明白。总之上面方法很多都是第一次见到,不是很理解。
match的使用说明

注意match使用中,使用/g和不使用的区别,在match中表达式使用了(),但是没有使用/g,那么会继续找()括号里的子表达式匹配。

Javascript原生base64编码解码函数btoa(atob)用法详解
可以将base64字符串还原成二进制格式(通常是原始的字符串,JavaScript中字符串就是一种序列化的二进制数据)
ArrayBuffer说明
ArrayBuffer这个真不知道使用情况。
如标题的问题,上传后服务器生成的图片无法查看,感觉这个js转的图片文件有问题,因为在服务器上打印二进制的json字符,都是一个A,大串的。有人可以告知吗?

this指针

快速理解JavaScript中this的用法与陷阱
JS属于运行期绑定,所以导致this的含义在运行过程中可能有多种变化。this和它声明环境无关,而完全取决于他的执行环境。

var name = '罗恩';
var aaa = {
    name: '哈利',
    say: function () {
        console.log(this.name);
    }
}

var bbb = {
    name: '赫敏',
    say: aaa.say
}

var ccc = aaa.say;

aaa.say();    //哈利
bbb.say();    //赫敏
ccc();        //罗恩

上面的代码执行结果,自己思考(不懂参考链接文档,应该不需要参考吧)
特殊的setTimeout 和 setInterval

var name = '罗恩';
var aaa = {
    name: '哈利',
    say: function () {
        setTimeout(function(){
            console.log(this.name);
        },1000);
    }
}
var bbb = {
    name: '赫敏',
    say: aaa.say
}
var ccc = aaa.say;
aaa.say();    //
bbb.say();    //
ccc();        //

三次输出的结果都是罗恩,这里就是解释了“this和它声明环境无关,而完全取决于他的执行环境”,setTimeout使里面的函数进行了异步执行,在执行的过程中,this的指向已经不是原有的对象了,而是window,所以输出了三个罗恩。想要预期结果的输出,可以做如下修改。

var name = '罗恩';
var aaa = {
    name: '哈利',
    say: function () {
        let that=this;
        setTimeout(function(){
            console.log(that.name);
        },1000);
    }
}

var bbb = {
    name: '赫敏',
    say: aaa.say
}

var ccc = aaa.say;

aaa.say();    //哈利
bbb.say();    //赫敏
ccc();        //罗恩

另外一种修改方法:

var name = '罗恩';
var aaa = {
    name: '哈利',
    say: function () {
        setTimeout(()=>{
            console.log(this.name);
        },1000);
    }
}

var bbb = {
    name: '赫敏',
    say: aaa.say
}

var ccc = aaa.say;

aaa.say();    //哈利
bbb.say();    //赫敏
ccc();        //罗恩

可以看到里面使用了es6的箭头函数。箭头函数中的this,指向与一般function定义的函数不同。
箭头函数this的定义:箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定。

var x=11;
var obj={
  x:22,
  say:function(){
    console.log(this.x)
  }
}
obj.say();
//console.log输出的是22
var x=11;
var obj={
 x:22,
 say:()=>{
   console.log(this.x);
 }
}
obj.say();
//输出的值为11

从上面的两段代码和结果,可以看出在普通函数里this是在运行时绑定的,obj.say()执行时,方法里的this指向的是obj。而箭头函数的this是在定义时绑定的,即在声明obj对象时,对象里的this就绑定了window。
如何解释箭头函数的this是在定义时绑定的

所谓的定义时候绑定,就是this是继承自父执行上下文中的this,比如这里的箭头函数中的this.x,箭头函数本身与say平级以key:value的形式,也就是箭头函数本身所在的对象为obj,而obj的父执行上下文就是window,因此这里的this.x实际上表示的是window.x,因此输出的是11。

来看看下面的一种特殊情况

var a=11
function test1(){
  this.a=22;
  let b=function(){
    console.log(this.a);
  };
  b();//输出11
  this.test=function(){
      console.log(this.a);
  }
  this.test();//输出22
}
var x=new test1();

这里执行b()并没有给定一个对象,所以默认的是window对象,所以输出的是11; this.test()的执行,那是因为对函数的调用制定了this。 继续下面的代码

var a=11
var obj={
    a:33,
    testObj:function(){
        this.a=22;
        let b=function(){
        console.log(this.a);
      };
      b();
    }
};
obj.testObj();

即便是这样,结果输出还是11。this跟函数在哪里定义没有半毛钱关系,函数在哪里调用才决定了this到底引用的是啥。也就是说this跟函数的定义没关系,跟函数的执行有大大的关系。所以,记住,“函数在哪里调用才决定了this到底引用的是啥”。this在function的误解。像上面这两种方法要先记住,再理解。

var a=11;
function test2(){
  this.a=22;
  let b=()=>{console.log(this.a)}
  b();
}
var x=new test2();
//输出22

有这样的一种理解:箭头函数中定义的时候绑定this的具体含义,应该继承的是父执行上下文里面的this,切忌是父执行上下文!!!这样就很多箭头函数中的指向不明确就迎刃而解了。
注意

声明一个普通的对象(非函数)是没有执行上下文的

深入理解ES6箭头函数中的this

apply、call

apply、call 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。使用这两个函数时,一定要清楚this是如何指向谁的。参考链接,知道如何使用call 和apply ,知道两者之间传参的区别,知道何种情况下选择哪个方法,知道那些场景下使用这两函数。

js正则表达式

js正则表达式及test、exec、match和replace方法使用,零宽断言
之前只使用了一些简单的正则表达式,test和replace的最基本的用法,甚至连在字符串中取个数字都是用split分割来获取,典型的metricId的获取;看完这篇文章感觉自己太low了,并且解决了自己对(?:)和之前在看其他代码match方法使用的不解。

正则表达式的创建方式

  • 字面量创建方式
  • 实例创建方式

var reg = /pattern/flags
// 字面量创建方式
var reg = new RegExp(pattern,flags);
//实例创建方式

pattern:正则表达式
flags:标识(修饰符)
标识主要包括:

  1. i 忽略大小写匹配
  2. m 多行匹配,即在到达一行文本末尾时还会继续寻常下一行中是否与正则匹配的项
  3. g 全局匹配 模式应用于所有字符串,而非在找到第一个匹配项时停止

字面量创建方式和构造函数创建方式的区别
1.字面量创建方式不能进行字符串拼接,实例创建方式可以

var regParam = 'cm';
var reg1 = new RegExp(regParam+'1');
var reg2 = /regParam/;
console.log(reg1);  //   /cm1/
console.log(reg2);  //  /regParam/

2.字面量创建方式特殊含义的字符不需要转义,实例创建方式需要转义

var reg1 = new RegExp('\d');  //    /d/ 
var reg2 = new RegExp('\\d')  //   /\d/
var reg3 = /\d/;              //  /\d/
  • 元字符
    代表特殊含义的元字符

\d : 0-9之间的任意一个数字 \d只占一个位置
\w : 数字,字母 ,下划线 0-9 a-z A-Z _
\s : 空格或者空白等
\D : 除了\d
\W : 除了\w
\S : 除了\s
. : 除了\n之外的任意一个字符
\ : 转义字符
| : 或者
() : 分组
\n : 匹配换行符
\b : 匹配边界 字符串的开头和结尾 空格的两边都是边界 => 不占用字符串位数
^ : 限定开始位置 => 本身不占位置
$ : 限定结束位置 => 本身不占位置
[a-z] : 任意字母 []中的表示任意一个都可以
[^a-z] : 非字母 []中^代表除了
[abc] : abc三个字母中的任何一个 [^abc]除了这三个字母中的任何一个字符

代表次数的量词元字符

  • : 0到多个
  • : 1到多个
    ? : 0次或1次 可有可无
    {n} : 正好n次;
    {n,} : n到多次
    {n,m} : n次到m次
  • 分组
    只要正则中出现了小括号那么就会形成一份分组
    只要有分组,exec(match)和replace中的结果就会发生改变
    分组的引用(重复子项):只要在正则中出现了括号就会形成一个分组,我们可以通过\n (n是数字代表的是第几个分组)来引用这个分组,第一个小分组我们可以用\1来表示
    例如:求出这个字符串'abAAbcBCCccdaACBDDabcccddddaab'中出现最多的字母,并求出出现多少次(忽略大小写)。
var str = 'abbbbAAbcBCCccdaACBDDabcccddddaab';
//将相同的字符弄在一起
    str = str.toLowerCase().split('').sort(function(a,b){return a.localeCompare(b)}).join('');

    var reg = /(\w)\1+/ig;
    var maxStr = '';
    var maxLen = 0;
    str.replace(reg,function($0,$1){
        var regLen = $0.length;
        if(regLen>maxLen){
            maxLen = regLen;
            maxStr = $1;
        }else if(maxLen == regLen){
            maxStr += $1;
        }
    })
    console.log(`出现最多的字母是${maxStr},共出现了${maxLen}次`)

st=>start: 用户登陆 op=>operation: 登陆操作 cond=>condition: 登陆成功 Yes or No? e=>end: 进入后台

st->op->cond cond(yes)->e cond(no)->op

A->B: Message
B->C: Message
C->A: Message

Clone this wiki locally