前端速记

687°C 12-06-2020
最近更新于:2024-01-08 14:33:01

文章摘要chatGPT

standby chatGPT responsing..

JavaScript 速记

日常记录一些 js/css 相对实用的小笔记,本笔记保持长期更新,如有错误或更好的方案留言反馈

使用 toString() 取随机字符串(toString 最大值为 32)

    var rs=(num)=>{let rs=Math.random().toString(num);return rs.substring(2,rs.length)}
rs(2);  //1011111100100110111101101110010000011101101001100001
rs(16);  //40a52a10becc

使用 link() 创建指定参数链接

    "example string".link("http://www.w3school.com.cn");  //<a href="http://www.w3school.com.cn">example string</a>"

使用 !+"v1" 判断 IE8 以下的浏览器

    !+"\v1";  //true(IE8及以下)
!+"\v1";  //false(谷歌浏览器和IE9及以上)

使用原生js选择 不包含特定 class 的元素(How to Select Element That Does Not have Specific Class)

    <ul id="tasks">
  <li class="completed selected">One Task</li>
  <li>Two Task</li>
</ul>

// select li which doesn't have a 'class' attribute...
console.log(document.querySelector("li:not([class])"))

// select li which doesn't have a '.completed' and a '.selected' class...
console.log(document.querySelector("li:not(.completed):not(.selected)"))

通过创建 input 并使用 document.execCommand("copy") 复制文本框内容(注意这里不能隐藏文本框否则获取不到值)

    var text="some sample text",  //文本内容
    copyIpt=document.createElement("input");  //创建文本框
//copyIpt.style.display="none";copyIpt.type="hidden";
document.body.appendChild(copyIpt);  //添加文本框
copyIpt.value=text;  //复制到文本框
copyIpt.select();  //选中所有文本
document.execCommand("copy")  //复制所选内容

js内容选中即复制

    document.onclick = function() {
    if (window.getSelection) {
        text = window.getSelection();
    } else if (document.selection) {
        text = document.selection.createRange();
    }
    // 放到粘贴板里,操作浏览器自身的API
    // console.log(text.toString());
    document.execCommand('Copy'); // 执行浏览器的复制命令
}

(更新精准/模糊匹配)js 正则匹配指定开头结尾内字符串(这里匹配 img 标签)

    var str = "img: <img src='#' />",
    filter = str.match(/\<img.*?\>/g);  //<img src='#' />

    var str = "img: <img src='#' />",
    inclouds = str.match(/\<([\s\S]*?)\>/)[0],  //<img src='#' />
    notincloud = str.match(/\<([\s\S]*?)\>/)[1];  //img src='#' /

js 删除符合指定条件的数组对象中的某个对象

    var arr = [{name:"a",age:1},{name:"b",age:2},{name:"c",age:3}];
console.log(arr)  //a:1 b:2 c:3
for(let i=0;i<arr.length;i++){
    arr[i].name=="b" ? arr.splice(i,1) : false;
}
console.log(arr)  //a:1 c:3

js 函数参数执行 js 方法

    var arr = ["a","b","c"],
    forArr = forFunc=(arr,exe)=>{
        if(arr!=null && arr!=undefined)
        for(let i=0;i<arr.length;i++){
            exe!=undefined ? exe(i) : false;
        }
    };
forFunc(arr,function(i){
    console.log(arr[i])  //a,b,c
})

js 批量定义变量

    var arr = ["a","b","c"],
for (let i=0; i<arr.length;i++) {
    eval('var' +arr[i]+ '= document.getElementById("' +arr[i]+ '");');
}
console.log(a);  //确保 id 为 a 的元素不等于 null 或 undefined 

js Object.keys 用法举例

    var arr = ["a","b","c"],
    obj = {"a":"aaa","b":"bbb","c":"ccc"},
    str = "String";
Object.keys(arr);  //["0","1","2"]
Object.keys(obj);  //["a","b","c"]
Object.keys(str);  //["0","1","2","3","4","5"]

JavaScript 异步方案 async/await

    const f = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(123);
    }, 2000);
  });
};

const testAsync = async () => {
  const t = await f();
  console.log(t);
};

testAsync();
//首先定义了一个函数 f,这个函数返回一个 Promise,并且会延时 2 秒,resolve 并且传入值 123。
//testAsync 函数在定义时使用了关键字 async,然后函数体中配合使用了 await,最后执行 testAsync。
//整个程序会在 2 秒后输出 123,也就是说 testAsync 中常量 t 取得了 f 中 resolve 的值,并且通过 await 阻塞了后面代码的执行,直到 f 这个异步函数执行完。

js 移除 string 中的空格

    var str = "s triing",
    str = str.replace(/\s+/g,"");  //去除所有空格
    去除两头空格:   
    str = str.replace(/^\s+|\s+$/g,"");  //去除左空格
    str = str.replace( /^\s*/, '');  //去除右空格
    

js 移除指定数组中的某一项

    var arr = ["a","b","c"];
    let index = arr.indexOf("b");
    arr.splice(index,1);
    console.log(arr)  //["a","c"]

js 防抖(连续点击)

    function debounce(fn, wait) {    
    var timeout = null;    
    return function() {
        if(timeout !== null)   clearTimeout(timeout);        
        timeout = setTimeout(fn, wait);    
    }
}
// 处理函数
function handle() {
    console.log("handled 1000ms")
}
// 执行事件
window.addEventListener('click', debounce(handle, 1000));

    var check;
window.onclick=()=>{
    check ? clearTimeout(check) : check;
    check = setTimeout(function(){
        console.log('checked');
    }, 1000);
}

js 自执行函数

    (function a(){
    console.log('auto_run_fn')  //auto_run_fn(无需调用直接执行)
})()

js 自执行函数 this 指向

    (function(){
    console.log(this);  //this 指向 window
    var that = this;  //that 指向 window
    return (function(){
        return this
    })()
})();

JavaScript 闭包计数器

    function closure(){
        var counter = 0;
        plus = function(){
            counter++
        };
        subs = function(){
            counter--
        };
        //闭包函数
        return function(){
            console.log(counter)
        }
    };
var res = closure(),  //调用闭包函数
    counter_plus = function(){
        plus();
        res()
    },
    counter_subs = function(){
        subs();
        res()
    };
counter_plus();  //counter = 1
counter_subs();  //counter = 0

JavaScript 防抖(闭包)

    function debounce(delay){
        var timer = null;
        return function(){
            timer ? clearTimeout(timer) : timer;
            timer = setTimeout(function(){
                console.log("连续点击时,仅执行一次(最后一次)点击事件")
            },delay)
        }
    };
var res = debounce(1000);
window.addEventListener('click',res)  //连续点击时,仅执行一次(最后一次)点击事件

JavaScript 节流(闭包)

    function throttle(delay){
        var timer = null,
            handle = function(){
                console.log("连续点击时,每隔 1000ms 执行一次 handle()");
            };
        return function(){
            if(timer==null){  //!timer
                timer = setTimeout(function(){
                    //handle.apply(this,null);  //apply 传递 argument 上下文 this 环境
                    handle();
                    timer = null  //消除定时器表示激活
                },delay)
            }
        }
    };
var res = throttle(1000);
window.onclick=function(){
    res()  //连续点击时,每隔 1000ms 执行一次 handle()
}

JavaScript call()  apply()

    console.log(this);  //window
//call()、apply()、bind() 都是用来重定义 this 这个对象的!
var name="name",
    age=0;
var obj={
        name: "NAME",
        objAge: this.age,
        fn: function(arg){
            console.log(this);
            console.log("arg: "+arg);
        }
    },
    newObj={
        name: "Named",
        age: 1
    };
obj.fn();  //{NAME,0}
obj.fn.call(newObj,'string');  //{Named,1},"string"
obj.fn.apply(newObj,['array']);  //{Named,1},[array]
obj.fn.bind(newObj,'string')();  //{Named,1},"string"
obj.fn.bind(newObj,['array'])();  //{Named,1},[array]

JS正则限制只能输入数字、或带小数点的数字,并且小数后面限制多少位

    const length = 2
    const reg = new RegExp(`^\\d+(\\.\\d{1,${length}})?$`)

JS 利用 offsetParent 判断元素是否可见

    var p = document.querySelectorAll("p");
    p.offsetParent!=null ? console.log("可见") : console.log("不可见");

JS 利用 split()  join() 实现 replaceAll() 的两种方式

    var str = "[dog]man[cat]",
    replace = ["[","]"],
    all = ["【","】"],
    obj = {
        "[":"【",
        "]":"】"
    },
    replaceAll = function(str,replace,all){
        for(let i=0;i<replace.length;i++){
            str = str.split(replace[i]).join(all[i])
        };
        return str
    },
    replaceObj = function(str,obj){
        for(key in obj){
            str = str.split(key).join(obj[key])
        };
        return str
    };
    replaceAll(str,replace,all);  //"【dog】man【cat】"
    replaceObj(str,obj);  //"【dog】man【cat】"

Js 过滤字符串数字和非数字

    var str="a1b2c3";
console.log(str.replace(/[0-9]/ig,""));  //abc
console.log(str.replace(/[^0-9]/ig,""));  //123

Js 获取指定父元素

function eachParent(curPar,tarPar){
    while(curPar && curPar.nodeName.toLowerCase()!=tarPar){
        curPar = curPar.parentNode
    };
    return curPar
}

Js 在 head 执行时当所有 dom 加载完成后再执行

var headfn = function(){
    console.log("hellow world")
},
isloaded = function(){
    window.addEventListener("DOMContentLoaded", headfn, false);
}

Js 滚动到当前滚动条底部

var focusScroll = function(focusarea){
    focusarea.focus();
    focusarea.scrollTop = focusarea.scrollHeight
};
focusScroll(textarea)  //textarea 聚焦元素

Js textarea/input 值操作

var textarea = documen.getElementById("textarea")
    selection = window.getSelection ? window.getSelection() : document.selection.createRange().text,
    indexOfSelectBefore = textarea.selectionStart,
    indexOfSelectAfter = textarea.selectionEnd;
    textarea.setSelectionRange(0, 0);  //定位光标到指定位置(不选中)
    console.log(selection.toString());  //当前已选中文本
    console.log(indexOfSelectBefore);  //当前已选中文本前索引
    console.log(indexOfSelectAfter);  //当前已选中文本后索引

Js 使用 dispatchEvent 触发自定义事件

var event = new Event('click');
window.addEventListener('click',function(e){
    console.log(1)
});
window.dispatchEvent(event)  //log 1 without click the window

Js 获取最近一个月(上个月的今天至今为止)的 leancloud 标准日期格式

console.log(new Date());  //Tue Apr 27 2021 11:05:51 GMT+0800 (中国标准时间)
dateFormat = function(d){
    const addZero = (n,m) => {
              return n<m ? '0'+n : n;
          },
          year = d.getFullYear(),
          month = p ? addZero(d.getMonth()+1,10) : addZero(d.getMonth(),10),
          day = addZero(d.getDate(),10),
          hour = d.getHours(),
          minute = addZero(d.getMinutes(),10);
    return year+ '-' +month+ '-' +day+' '+hour+':'+minute+':'+second;
};
dateFormat(new Date(),true);  //2021-04-27 11:05:51
dateFormat(new Date(),false);  //2021-03-27 11:05:51

Js 获取当前元素到窗口顶部/侧面距离

var el = document.getElementById("el");
console.log(el.getBoundingClientRect().top)  //distance between el and window-top

获取 JS 数组中的相同元素的名称和数量

var ary =["anime","comic","game","movie","tv","anime"];  
var res = [];  
ary.sort();  
for(var i = 0;i<ary.length;){ 
    var count = 0;
    for(var j=i;j<ary.length;j++){  
        if(ary[i] == ary[j]){  
            count++;
        }
    };
    res.push([ary[i],count]);  
    i+=count;  
}  
//res 二维数维中保存了 值和值的重复数
for(var  i = 0 ;i<res.length;i++){  
    console.log("值:"+res[i][0]+" 重复次数:"+res[i][1]+");  
}


// 不用reduce时: 
    var arr = ["apple","orange","apple","orange","pear","orange"]; 
    function getWordCnt(){ 
      var obj = {}; 
      for(var i= 0, l = arr.length; i<l; i++){ 
        var item = arr[i]; 
        obj[item] = (obj[item] +1 ) || 1; 
      } 
      return obj; 
    }
    console.log(getWordCnt());//{apple: 2, orange: 3, pear: 1}
// 用reduce时: 
    var arr = ["apple","orange","apple","orange","pear","orange"]; 
    function getWordCnt(){ 
      return arr.reduce(function(prev,next){ 
        prev[next] = (prev[next] + 1) || 1; 
        return prev; 
      },{}); 
    } 
    console.log(getWordCnt());//{apple: 2, orange: 3, pear: 1}


Js 简单委托事件

<div id="atag">
    <a>111</a>
    <a>222</a>
</div>
const atag = document.querySelector("#atag");
atag.onclick=(e)=>{
    var e = e || window.event,
        t = e.target || e.srcElement,
        p = "a";  //事件标签
    // 创建 while 循环,直到 t=p,否则循环向上遍历 t 的 parentNode 是否为 p
    while(t!=atag && t!=null){
        if(t.nodeName.toLowerCase()==p){
            console.log("delegated a tag");
            break;  //跳出循环
        }else{
            t = t.parentNode;
        }
    }
}

Js 在 iframe 中查找父页面变量或函数

var variable = "parentvar";
<iframe>
    console.log(parent.variable)  //parentvar
</iframe>

Js 利用访问 iframe 父页面变量

var parVar = "this var from parent";  //注意!不能使用 const 否则 iframe 不可读父页面变量
//iframe 页面内调用
console.log(parent.parVar)  //"this var from parent"

Js 利用 postMessage 方法在 iframe 中与父页面跨域通信

<iframe id="postMessage"></iframe>

//子页面传数据至父页面同理
const person = {
          name: "name",
          age: 1
      };
window.onload = function(){
    document.getElementById("postMessage").contentWindow.postMessage(JSON.stringify(person),"/")  //postMessage 第二参数可限制访问来源
};
//iframe 页面内调用
window.addEventListener("message",function(e){
    let res = JSON.parse(e.data);  //return parsed JSON Object
    alert(`getMessage ${res} from ${e.origin}`);  //getMessage [Object Object] from /
    console.log(res)  //{name: "name",age: 1}
});

正则匹配指定标签内所有内容

<tag>[\w\W]*?</tag>

短路运算符 && || (除了NaN、null、””、undefined、0、function这几个为false外,其他皆为true)

false ? false : true
console.log(false&&true)  //false (find true one by one)
console.log(false||true)  //true (find true between both)

JS 鼠标拖拽时被中断

event.preventDefault()  //阻止默认事件 

element.setCapture()  //捕获事件
element.releaseCapture()  //释放事件 

js 时间戳转为日期格式

function getLocalTime(nS) {     
    return new Date(parseInt(nS) * 1000).toLocaleString().replace(/:\d{1,2}$/,' ');     
}     
console.log(getLocalTime(1293072805));  //2010/12/23 上午10:53 

JS阻止事件冒泡

e=e || window.event,
//阻止事件冒泡
//不仅仅要stopPropagation,还要preventDefault
pauseEvent = function(e){
    if(e.stopPropagation) e.stopPropagation();
    if(e.preventDefault) e.preventDefault();
    e.cancelBubble=true;
    e.returnValue=false;
    return false;
}

js 获取指定 css 值(transform),不指定即返回所有匹配值

_getComputedStyle = function(element,property,which) {
    const st = window.getComputedStyle(element, null),
          tr = st.getPropertyValue('-webkit-'+property) ||
               st.getPropertyValue('-moz-'+property) ||
               st.getPropertyValue('-ms-'+property) ||
               st.getPropertyValue('-o-'+property) ||
               st.getPropertyValue(property) || 'FAIL';
    if (tr === 'FAIL') {
        return '';
    };
    if(which){
        let target = tr.split(",")[which];
        if(target){
            return Number(target)
        }else{
            return 0
        }
    }else{
        return tr
    }
}

safari 父元素 overflow 子元素 transform 导致父元素 border-radius 失效

.father{
    border-radius: 10px;
    overflow: hidden;
    transform: rotate(0deg);  //仅需在设置 border-radius 的元素上添加 rotate(0deg) 即可修复
}
.child{
    transform: translate(10px,10px)
}

调用 call 改变调用函数 this 指向,并调用其对象成员

var obj = {
  name: 'andy',
  age: 10,
  sex: 'boy'
};
function func(a, b) {
  console.log(this);
  console.log(a + b);
};

function cons(name, age, sex) {
  this.name = name;
  this.age = age;
  this.sex = sex;
  this.desc = 'my name is '+name+', i am a '+age+' years old '+sex;
  return this
};
function use(n, a, s){
  cons.call(this, n, a, s)
}

func(1, 2);  // return 3 (Window Object)
func.call(obj, obj.age, 2);  // return 12 (obj Object)

cons(obj.name, obj.age, obj.sex);  // Window Object
cons.call(obj, obj.name, obj.age, obj.sex);  // obj Object

var usage = new use('刘德华', 18, '男');
console.log(usage);

apply 改变 this 数组参数

var o = {
  name: 'andy',
};

function fn(arr) {
  console.log(this);
  console.log(arr); // 'pink'
}
fn.apply(o, ['pink']);
// 1. 也是调用函数 第二个可以改变函数内部的this指向
// 2. 但是他的参数必须是数组(伪数组)
// 3. apply 的主要应用 比如说我们可以利用 apply 借助于数学内置对象求数组最大值
// Math.max();
var arr = [1, 66, 3, 99, 4];
var arr1 = ['red', 'pink'];
// var max = Math.max.apply(null, arr);
var max = Math.max.apply(Math, arr);
var min = Math.min.apply(Math, arr);
console.log(max, min);

按照一定的模式,从数组或对象中提取值,将提取出来的值赋值给另外的变量

let ary = [1, 2, 3];
let [a, b, c, d] = ary;
console.log(a);
console.log(b);
console.log(c);
console.log(d); // undefined

let person = { name: 'lisi', age: 30, sex: '男' };
let { name, age, sex } = person;
console.log(name);
console.log(age);
console.log(sex);

let { name: myName } = person;
console.log(myName);

ES6 箭头函数 this 指向

var age = 100;
var obj = {
  age: 20,
  say: () => {
    console.log(this.age);  // Window
  },
  says: function(){
    console.log(this.age);  // obj
  }
};
obj.say(); // 100
obj.says(); // 20

将一个不定数量的参数表示为一个数组

const sum = (...args) => {
  let total = 0;
  args.forEach((item) => (total += item));
  return total;
};
console.log(sum(10, 20));  // 30
console.log(sum(10, 20, 30));  // 60

// 解构 ...args
let ary1 = [1, 2, 3];
let [s1, ...s2] = ary1;
console.log(s1);  // 1
console.log(s2);  // [2,3]

扩展运算符应用于数组合并

let ary1 = [1, 2, 3];
let ary2 = [4, 5, 6];
// ...ary1 // 1, 2, 3
// ...ary1 // 4, 5, 6
let ary3 = [...ary1, ...ary2];
console.log(ary3);  // [1,2,3,4,5,6]

ary1.push(...ary2);
console.log(ary1);  // [1,2,3,4,5,6]

利用扩展运算符将伪数组转换为真正的数组

<div>1</div>
<div>2</div>
<div>3</div>
<script>
  var oDivs = document.getElementsByTagName('div');
  console.log(oDivs);
  var ary = [...oDivs];
  ary.push('a');
  console.log(ary);
</script>

找出第一个符合条件的数组成员,如果没有找到返回 undefined

var ary = [
  {
    id: 1,
    name: '张三',
  },
  {
    id: 2,
    name: '李四',
  },
];
let target = ary.find((item) => item.id >= 2);
console.log(target);  // {id: 2, name: '李四'}

找出第一个符合条件的数组成员的位置,如果没有找到返回-1

let ary = [10, 20, 50];
let index = ary.findIndex((item) => item > 15);
console.log(index);

某个数组是否包含给定的值,返回布尔值

let ary = ['a', 'b', 'c'];
let result = ary.includes('a');
console.log(result); // true
result = ary.includes('e');
console.log(result); // false

startsWith() 和 endsWith()

let str = 'Hello ECMAScript 2015';
console.log(str.startsWith('Hello'));  // true
console.log(str.endsWith('2016'));  // false

闭包案例

// 2. 利用闭包的方式得到当前小li 的索引号
for (var i = 0; i < lis.length; i++) {
  (function (i) {
    lis[i].onclick = function () {
      console.log(i);
    };
  })(i);
}

// 闭包应用-3秒钟之后,打印所有li元素的内容
var lis = document.querySelector('.nav').querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(lis[i].innerHTML);
    }, 3000);
  })(i);
}

// 打车起步价13(3公里内),  之后每多一公里增加 5块钱.  用户输入公里数就可以计算打车价格
// 如果有拥堵情况,总价格多收取10块钱拥堵费
// function fn() {};
// fn();
var car = (function () {
  var start = 13; // 起步价  局部变量
  var total = 0; // 总价  局部变量
  return {
    // 正常的总价
    price: function (n) {
      if (n <= 3) {
        total = start;
      } else {
        total = start + (n - 3) * 5;
      }
      return total;
    },
    // 拥堵之后的费用
    yd: function (flag) {
      return flag ? total + 10 : total;
    },
  };
})();
console.log(car.price(5)); // 23
console.log(car.yd(true)); // 33


//闭包隐藏数据
function createCache(){
	const data = {} //隐藏闭包中的数据不被外界访问
	return {
		set:function(key,val){
			data[key] = val
		},
		get:function(key){
			return data[key]
		}
	}
}
const c = createCache()
c.set('a',100)
console.log(c.get('a')) //100

// 闭包执行一次函数
function closure_once(fn,data){
    let flag = false;
    return function(){
        if(!flag){
            flag=true;
            if(data){
                return fn.call(this,...arguments)
            }else{
                fn.call(this,...arguments);
            }
        }
    }
}
function sum(a,b){
    console.log(a+b);
}
function sum_data(a,b){
    return a+b;
}
let sum_once = closure_once(sum),
    sum_once_data = closure_once(sum,true);
sum_once(1,2);  // 3
sum_once(1,2);  // ..
sum_once_data(1,2);  // return 3
sum_once_data(1,2);  // ..

//闭包事件绑定
function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}
var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;

递归函数(函数内部调用函数自身,满足条件循环调用)

//求 1 * 2 * 3 ... * n 阶乘
function fn(n) {
  if (n == 1) {
    return 1;
  } else {
    return n * fn(n - 1);
  }
}
console.log(fn(3));
console.log(fn(4));
// 根据 id 返回对应的数据对象..

js正则括号

// 中括号 字符集合.匹配方括号中的任意字符.
var reg = /^[abc]$/;
// a 也可以 b 也可以 c 可以  a ||b || c
// 大括号  量词符. 里面表示重复次数
var reg = /^abc{3}$/; // 它只是让c重复三次   abccc
console.log(reg.test('abc'));
console.log(reg.test('abcabcabc'));
console.log(reg.test('abccc'));  // true

// 小括号 表示优先级
var reg = /^(abc){3}$/; // 它是让abc重复三次
console.log(reg.test('abc'));
console.log(reg.test('abcabcabc'));  // true
console.log(reg.test('abccc'));

CLASS 类的基础构造方法

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  say() {
    console.log(this.name + '你好');
  }
}

var ldh = new Person('刘德华', 18);
ldh.say();

CLASS 子类继承父类属性和方法

class Father {
  constructor() {}
  money(c) {
    let coins = 100;
    c ? coins=coins/2 : coins;
    console.log(coins)
  }
}

new Father().money();  // 100

class Son extends Father {}
var son = new Son();
son.money(true);  // 100/2

CLASS super 关键字继承中的属性或者方法

// 父类有加法方法
class Father {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  sum() {
    console.log(this.x + this.y);
  }
}
// 子类继承父类加法方法 同时 扩展减法方法
class Son extends Father {
  constructor(x, y) {
    // 利用super 调用父类的构造函数
    // super 必须在子类this之前调用
    super(x, y);
    this.x = x;
    this.y = y;
  }
  subtract() {
    console.log(this.x - this.y);
  }
}
var son = new Son(5, 3);
son.subtract();
son.sum();

构造函数中的静态、实例成员

// 构造函数中的属性和方法我们称为成员, 成员可以添加
function Star(uname, age) {
  this.uname = uname;
  this.age = age;
  this.sing = function () {
    console.log('我会唱歌');
  };
}
var ldh = new Star('刘德华', 18);
// 1.实例成员就是构造函数内部通过this添加的成员 uname age sing 就是实例成员
// 实例成员只能通过实例化的对象来访问
console.log(ldh.uname);
ldh.sing();
// console.log(Star.uname); // 不可以通过构造函数来访问实例成员
// 2. 静态成员 在构造函数本身上添加的成员  sex 就是静态成员
Star.sex = '男';
// 静态成员只能通过构造函数来访问
console.log(Star.sex);
console.log(ldh.sex); // 不能通过对象来访问

在循环中使用 setinterval 并在内部清除定时器

// 关键点:勿直接在循环内定义使用定时器,需要封装为函数后再循环内调用,否则无法终止定时器
function interval(i){
    var interval = setInterval(function(){
        i++;
        i>10 ? clearInterval(interval) : false;
        console.log(i);  // i>10 终止运行
    }, 10);
}
for(let i=0;i<list.length;i++){
    interval(i);  // i>10 (正常)终止运行
    // var interval = setInterval(function(){
    //     i++;
    //     i>10 ? clearInterval(interval) : false;
    //     console.log(i);  // 达成条件后无法终止运行
    // }, 10);
}

正则函数匹配中英文字符串数量

const cn_text = "世界,你好!",
      en_text = "You forget a thousand things every day. How about you make sure this is one of them?",
      mx_text = "世界,You forget a thousand things every day. 你好!How about you make sure this is one of them?";
var cn_count = (str, out=true)=>{
        let res = str.match(/\p{sc=Han}/gu);
        return out ? res.length : res;
    },
    en_count = (str, out=true)=>{
        let res = str.replace(/[^\w-]/g, ' ').split(/\s+/).filter(w => {
            return ['', '-', '_'].indexOf(w.trim()) === -1
        });  //str.replace(/[^\w-]/g, ' ').trim().split(/\s+/)
        return out ? res.length : res;
    },
    mx_count = (str, out=true)=>{
        let cn = str.match(/\p{sc=Han}/gu),
            en = str.replace(/[^\w-]/g, ' ').split(/\s+/).filter(w => {
                return ['', '-', '_'].indexOf(w.trim()) === -1
            }),
            arr = [cn,en];
        if(out){
            if(cn && en){
                return cn.length + en.length;
            }else if(cn){
                return cn.length;
            }else if(en){
                return en.length;
            }else{
                return arr
            }
        }else{
            return arr
        }
    };
//中文
cn_count(cn_text);  //4
cn_count(cn_text, false);  //(4) ['世', '界', '你', '好']
//英文
en_count(en_text);  //17
en_count(en_text, false);  /* (17) ['You', 'forget', 'a', 'thousand', 'things', 'every', 'day', 'How', 'about', 'you', 'make', 'sure', 'this', 'is', 'one', 'of', 'them'] */
//混合
mx_count(cn_text);  //4
mx_count(en_text);  //17
mx_count(mx_text);  //21
mx_count(mx_text, false);  //(2) [Array(4), Array(17)]

递归实现“由快变慢”定时器

// https://www.cnblogs.com/wxy0/p/13496025.html
var counter = 0;
var myFunction = function(){
    clearInterval(interval);
    counter++;
    interval = setInterval(myFunction, counter);  //内部调用函数本身
    console.log(counter)
}
var interval = setInterval(myFunction, counter);

js监听滚动视图实现 lazyLoad 懒加载

// lazyload js https://www.jb51.net/article/216692.htm
const bodyimg = document.querySelectorAll("img");
if(bodyimg.length>=1){
    for(let i=0;i<bodyimg.length;i++){
        let eachimg = bodyimg[i],
            datasrc = eachimg.dataset.src;
        eachimg.getBoundingClientRect().top < window.innerHeight ? eachimg.src = datasrc : false; //检查并加载当前视图页面图片
        window.addEventListener('scroll', function(){
            if(eachimg.getBoundingClientRect().top < window.innerHeight){ // height-sheight<=wheight 判断图片是否将要出现
                eachimg.src = datasrc; // 出现后将自定义地址转为真实地址
            }
        })
    }
}

js 图片懒加载集成函数封装(异步监听,滚动节流控制,加载延迟,错误处理,RAF支持等)

function loadlazy(imgs,offset=0,scroll=true){
    const imglist = document.querySelectorAll(imgs),
          loadimg = "https://img.2broear.com/images/loading_3_color_tp.png",
          raf_available = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
    if(imglist.length<=0) return;
    var timer_throttle = null,
        loadArray = [...imglist],
        time_delay = 500,
        msgObject = Object.create(null),
        autoLoad = function(imgLoadArr){
            for(let i=0,arrLen=imgLoadArr.length;i<arrLen;i++){
                let eachimg = imgLoadArr[i],
                    datasrc = eachimg.dataset.src;
                eachimg.src = loadimg; //pre-holder(datasrc only)
                new Promise(function(resolve,reject){
                    resolve(imgLoadArr);
                }).then(function(res){
                    if(eachimg.getBoundingClientRect().top>=window.innerHeight || eachimg.offsetParent==null) return;
                    // var temp = new Image();
                    // temp.src = datasrc;  //请求一次
                    // temp.onload = function(){
                        eachimg.src = datasrc; // 即时更新 eachimg(设置后即可监听图片 onload 事件)
                        // 使用 onload 事件替代定时器或Promise,判断已设置真实 src 的图片加载完成后再执行后续操作
                        eachimg.onload=function(){
                            if(this.getAttribute('src')===datasrc){
                                res.splice(res.indexOf(this), 1);  // 移除已加载图片数组(已赋值真实 src 情况下)
                            }else{
                                this.removeAttribute('data-src'); // disable loadimg
                                this.src = datasrc;  // this.src will auto-fix [http://] prefix
                                time_delay = 1500;  //increase delay (decrease request)
                                console.log(time_delay);
                            }
                        };
                        // handle loading-err images eachimg.onerror=()=>this.src=loadimg;
                        eachimg.onerror=function(){
                            res.splice(res.indexOf(this), 1);  // 移除错误图片数组
                            this.removeAttribute('src');
                            this.removeAttribute('data-src'); // disable loadimg
                            this.setAttribute('alt','图片请求出现问题'); // this.removeAttribute('src');
                        };
                    // }
                }).catch(function(err){
                    console.log(err);
                });
            }
        },
        scrollLoad = function(){
            return (function(){
                if(timer_throttle==null){
                    timer_throttle = setTimeout(function(){
                        if(loadArray.length<=0){
                            console.log(Object.assign(msgObject, {status:'lazyload done', type:'call'}));
                            window.removeEventListener('scroll', scrollLoad, true);
                            return;
                        };
                        autoLoad(loadArray);
                        // console.log('throttling..',loadArray);
                        timer_throttle = null;  //消除定时器
                    }, time_delay, loadArray); //重新传入array(单次)循环
                }
            })();
        };
    autoLoad(loadArray);
    // requestAnimationFrame support
    if(!scroll) return;
    window.addEventListener('scroll', function(event){
        let e = event || window.event,
            t = e.target || e.srcElement;
        if(t!==document) return;
        raf_available ? window.requestAnimationFrame(scrollLoad) : scrollLoad();
    }, true);
}

正则表达式中$1, $2

// 将yyyy-mm-dd格式转换为年月日格式
 function chDate1date(str){
    var reg =/(\d{4})\-(\d{2})\-(\d{2})/;
    return str.replace(reg,"$1年$2月$3日")
 };
chDate1date('2019-08-28');  // $1指2019,$2指08,$3指28

js中++num和num++在赋值时的区别

var num_ = 0;
console.log(num_++);  //0 后计算,此时num已被赋值1;

var _num = 0;
console.log(++_num)l  //1 先自加然后将自加后的值用做计算值

JS Promise 异步数据处理 + 链式回调

function newPromise(parm=1){
    return new Promise((resolve, reject)=>{
        parm ? resolve(parm) : reject(['rejected',0]);  //异步操做
    });
}
newPromise().then((res)=>{
    console.log('origin',res);  //直接返回 resove/reject 数据
    // res++; //预计算res
    return new Promise((resolve, reject)=>{
        console.log('lastest',res);  //链式回调上次 promise 数据
        resolve(++res);
        console.log('++',res);  //链式回调更新 promise 数据
    });
}).then((res)=>{
    // res++; //预计算res
    return new Promise((resolve, reject)=>{
        console.log('lastest',res);  //链式回调上次 promise 数据
        resolve(++res);
        console.log('++',res);  //链式回调更新 promise 数据
    });
}).catch((err)=>{
    console.log(err);
});

js 判断对象

function isObj(obj){
    return Object.prototype.toString.call(obj)==='[object Object]';
}
isObj(Object.create(null));  //true

JS 对象深拷贝

var deepCopy = (obj) => {
    var ret = {}
    for (var key in obj) {
        var value = obj[key]
        ret[key] = typeof value === 'object' ? deepCopy(value) : value
    }
    return ret
}

JS闭包模拟私有方法 闭包 – JavaScript | MDN (mozilla.org)

//闭包(匿名函数单次调用)
var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function(i=1) {
      changeBy(i);
    },
    decrement: function(d=1) {
      changeBy(-d);
    },
    value: function() {
      return privateCounter;
    }
  }
})();
console.log(Counter.value()); /* logs 0 */
Counter.increment(); /* logs 1 */
Counter.increment(10); /* logs 11 */
Counter.decrement(); /* logs 10 */
Counter.decrement(10); /* logs 0 */

//闭包(声明函数多次调用)
var makeCounter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function(i=1) {
      changeBy(i);
    },
    decrement: function(d=1) {
      changeBy(-d);
    },
    value: function() {
      return privateCounter;
    }
  }
};
var counter1 = makeCounter();
counter1.value(); /* logs 0 */
counter1.increment(); /* logs 1 */
counter1.increment(10); /* logs 11 */
counter1.decrement(); /* logs 10 */
counter1.decrement(10); /* logs 0 */
// 每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境。然而在一个闭包内对变量的修改,不会影响到另外一个闭包中的变量。
var counter2 = makeCounter();
counter2.value(); /* logs 0 */
counter2.increment(); /* logs 1 */
counter2.increment(10); /* logs 11 */
counter2.decrement(); /* logs 10 */
counter2.decrement(10); /* logs 0 */

JS构造对象方法到原型(取消闭包优化性能)

function MyObject(name, message) {
    this.name = name.toString();
    this.message = message.toString();
    // 以下方法造成每次调用构造器时,方法都会被重新赋值一次
    // this.getName = function() {
    //   return this.name;
    // };
    // this.getMessage = function() {
    //   return this.message;
    // };
}

function MyObject(name, message) {
    this.name = name.toString();
    this.message = message.toString();
}
// 避免使用闭包,在原型中设置对象共享方法
MyObject.prototype.getName = function() {
return this.name;
};
MyObject.prototype.getMessage = function() {
return this.message;
};

class类的创建与继承

class Polygon {
  constructor(height, width) {
    this.name = 'Polygon';
    this.height = height;
    this.width = width;
  }
}

// 重复声明一个类会引起类型错误
class Square extends Polygon {
  constructor(length) {
    super(length, length);  //构造函数中使用的 super() 只能在构造函数中使用,并且必须在使用 this 关键字前调用
    this.name = 'Square';
  }
}

break 中止当前执行 functions 函数

(function() {
    block_1: {
        console.log('1');
        break block_1;
        console.log('2'); // Skiped
    }
})();

JS export/import 模块重定向

// childModule1.js 中
let myFunction = ...; // assign something useful to myFunction
let myVariable = ...; // assign something useful to myVariable
export {myFunction, myVariable};

// childModule2.js 中
let myClass = ...; // assign something useful to myClass
export myClass;

// parentModule.js 中
// 仅仅聚合 childModule1 和 childModule2 中的导出
// 以重新导出他们
export { myFunction, myVariable } from 'childModule1.js';
export { myClass } from 'childModule2.js';


// 顶层模块中
// 我们可以从单个模块调用所有导出,因为 parentModule 事先
// 已经将他们“收集”/“打包”到一起
import { myFunction, myVariable, myClass } from 'parentModule.js'

js对象原型(在原型上定义方法)

const personPrototype = {
  greet() {
    console.log(`你好,我的名字是 ${this.name}!`);
  },
};
function Person(name) {
  this.name = name;
}
Object.assign(Person.prototype, personPrototype);

// new Person(123).__proto__
console.log(new Person('test').greet()); // 你好,我的名字是 test!

console.log(Object.hasOwn(irma, "name")); // 自有属性
console.log(Object.hasOwn(irma, "greet")); // false

原型与继承
例如,如果我们正在为一所学校建模,我们可能有教授和学生:他们都是人,所以有一些共同的特征(例如,他们都有名字),但每个人都可能增加额外的特征(例如,教授有一个他们所教的科目),或者可能以不同的方式实现同一个特征。在一个 OOP 系统中,我们可以说教授和学生都继承自人。

构造函数类与实例

const Person={
    name: '',
    teaches: '',
    constructor: function(name,teaches){
        Person.name = this.name = name;
        Person.teaches = this.teaches = teaches;
        Object.assign(Person.constructor.prototype, Person.methods);
    },
    methods:{
        intro() {
            //'this' is Person.constructor()
            return 'i am '+this.name+', i teaches '+this.teaches;
        }
    }
}
const a = new Person.constructor('a',1);
a; //[[prototype]] method->intro
a.name; //a
a.teaches; //1
a.intro(); //'i am a, i teaches 1'

解构赋值函数提取值

function parseProtocol(url) {
  const parsedURL = /^(\w+):\/\/([^/]+)\/(.*)$/.exec(url);
  if (!parsedURL) {
    return false;
  }
  console.log(parsedURL);
  // ["https://developer.mozilla.org/zh-CN/docs/Web/JavaScript",
  // "https", "developer.mozilla.org", "zh-CN/docs/Web/JavaScript"]

  const [, protocol, fullhost, fullpath] = parsedURL;
  return protocol;
}

parseProtocol("https://developer.mozilla.org/zh-CN/docs/Web/JavaScript");  //https

解构对象函数参数传递(默认只及自定义变量)

const user = {
  id: 42,
  displayName: "jdoe",
  fullName: {
    // firstName: "Jane",
    lastName: "Doe",
  },
};
function whois({ displayName=1, fullName:{firstName: name=2}, default_key=3 }) {
  return `${displayName} is ${name} nor ${default_key}`;
}

whois(user); // "jdoe is Jane"

for 循环迭代解构

const people = [
  {
    name: "Mike Smith",
    family: {
      mother: "Jane Smith",
      father: "Harry Smith",
      sister: "Samantha Smith",
    },
    age: 35,
  },
  {
    name: "Tom Jones",
    family: {
      mother: "Norah Jones",
      father: "Richard Jones",
      brother: "Howard Jones",
    },
    age: 25,
  },
];
for({name: n,family: { father: f }} of people){
    console.log(`Name: ${n}, Father: ${f}`);
}
// Name: Mike Smith, Father: Harry Smith
// Name: Tom Jones, Father: Richard Jones
for(let i=0;i<people.length;i++){
    const {name:n,family:{father:f}} = people[i];
    console.log(`Name: ${n}, Father: ${f}`);
}

组合数组对象解构(对象查找原型链)

const props = [
  {
      id: 1, 
      name: "Fizz",
      __proto__: {
          prot: "Fizz Prototype"
      }
  },
  { id: 2, name: "Buzz" },
  { id: 3, name: "FizzBuzz" },
];
const [{prot}, {id}, {name}] = props;
//prot "Fizz Prototype"
//id "2"
//name "FizzBuzz"

Javascript 面向对象OO 寄生组合继承(Object.create 可平替 object/inheritPrototype 但无法增强 constructor)

只调用了一次SuperType构造函数,并且因此避免了在SubType.prototype上面创建不必要的、多余的属性。

与此同时,原型链还能保持不变;因此,还能够正常使用instanceof和isPrototypeOf()。

function object(o){
    function F(){}
    F.prototype = o;
    // 返回浅复制传入对象 o 构造函数 F 原型
    return new F();
}
function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype);       //创建对象
    prototype.constructor = subType;                   //增强对象
    subType.prototype = prototype;                     //指定对象
}

function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};

function SubType(name, age){  
    SuperType.call(this, name);
    this.age = age;
}

inheritPrototype(SubType, SuperType);
// SubType.prototype = Object.create(SuperType.prototype);

SubType.prototype.sayAge = function(){
    alert(this.age);
};

var instance1 = new SubType("Nicholas", 29);

模块私有变量共有方法

var singleton = function(){

    //私有变量和私有函数
    var privateVariable = 10;

    function privateFunction(){
        return false;
    }

    //特权/公有方法和属性
    return {

        publicProperty: true,

        publicMethod : function(){
            privateVariable++;
            return privateFunction();
        }

    };
}();

对象函数节流

var processor = {
    timeoutId: null,
    //实际进行处理的方法
    performProcessing: function(){
        console.log('processing..', this);
    },
    //初始处理调用的方法
    process: function(){
        clearTimeout(this.timeoutId);
        var that = this;
        this.timeoutId = setTimeout(function(){
            that.performProcessing();
        }, 1000);
    }
};

//尝试开始执行 
let processing = processor.process.bind(processor);  // binding processor context
window.addEventListener('scroll', processing);  // bind event

JS 理论

队列任务执行顺序:Tasks, microtasks, queues and schedules – JakeArchibald.com

console.log(1); // 直接执行

setTimeout(function() {
    console.log(2); // 进入宏任务队列
})

new Promise(function(resolve) {
    console.log(3); //直接执行
    resolve()
}).then(function() {
    console.log(4); // 进入微任务队列
})

console.log(5); // 直接执行

// 打印结果: 1、3、5、4、2

变量提升(隐式全局变量)与作用域链:var – JavaScript | MDN (mozilla.org)

console.log(a, b); //全局a=undefined, 全局b=undefined
var a = 1, b = 1;
function fn() {
    //此处访问的变量a为下方变量提升的局部变量:var a;//undefined,变量b为函数外的全局变量b;//1)
    console.log('a='+a, 'b='+b); //局部a=undefined, 全局b=1
    //此处设置:局部变量a=2(提升至函数内顶级作用域链); 全局变量b=2;
    var a=b=2; //等同于 var a=2;(变量提升) b=2;(全局修改)
    console.log('a='+a, 'b='+b); //局部a=2, 全局b=2
}
fn();
console.log(a, b); //全局a=1, 全局b=2

CSS 速记

使用 rgba(255, 255, 255, 0) 代替 transparent 兼容 safari 环境下 -webkit-linear-gradient 渐变透明变黑

body{
    /* transparent not working on safari */
    background: -webkit-linear-gradient(left,red 0%,transparent 100%);
    /* rgba works just fine on safari */
    background: -webkit-linear-gradient(left,red 0%,rgba(255, 255, 255, 0) 100%);
}

使用 prefers-color-scheme 进行浏览器亮/暗色默认行为切换

    @media (prefers-color-scheme: light) {
    body{
        color:white;
        background:black;
    }
}
@media (prefers-color-scheme: dark) {
    body{
        color:blank;
        background:white;
    }
}

 html 添加 scroll-behavior 属性实现平滑滚动(配合js原生api scroll/scrollTo/scrollBy 使用)

    html{
    scroll-behavior: smooth;
}

鼠标经过文字后划过高亮背景


a:hover{
  background-size: 100% 30%;
}
a{
  transition: background-size .5s ease;
  background: linear-gradient(red 0%, red 100%) no-repeat left 87%/0 30%;
}

笔记参考链接: HOE:JavaScript 之神妙之处ECMAScript6 基础语法 | Gahotx’s blogJavaScript 函数进阶 | Gahotx’s blog


评论留言

既来之则留之~ 欢迎在下方留言评论,提交评论后还可以撤销或重新编辑。(Valine 会自动保存您的评论信息到浏览器)