前端0:js,css基础

1.js是按顺序执行的,故把 <script> 内容放到 <head> 里,或放到 <body> 内容之前,与<script> 内容放到 <body> 内容之后 执行的效果会有所不同。经常会遇到:

  ①<head><script> 里修改图片路径 obj.src 失败,由于未加载 window.onload。

2.节点处理

  由于浏览器兼容性差异,各标签之间的空白也算为节点,index 随之变化。

3.查询字符串:JS与服务器的通信,避免URL等数据格式不正确即未经编码,导致通信错误。

1 function addQueryStringArg(url,name,value){
2 if(url.index("?")==-1){
3 url+="?";
4 }else{
5 url+="&";
6 }
7 url+=encodeURLComponent(name)+"="+encodeURLComponent(value);
8 return url;
9 }

4.数组处理:数组其实和对象一样,也是有属性的,即 0,1,2,3...,所以才能用下标查找,同时可以用原型链查找属性的方法 key in array。

  arr=null 数组删除

  arr.pop 去尾,返回尾巴

  arr.join('.')   数组转字符串,以 . 分开,一般配合 split

  arr.reduce(fn)  接收一个函数进行两两迭代,数组中的每个值(从左到右)开始合并,最终计算为一个值。

  arr.map(fn,cb)   参数为函数表达式及回调,fn(a,b,c) 参数默认为当前数组值,当前数组值索引,etc  

  arr.shift() 删除头,返回头

  arr.unshift('a') 加头,返回length

  arr.push 加尾,返回length

  arr.splice(index,howmany,...itemn) 添加删除,返回原arr,index表示操作位置,index初始为0;howmany表示删除个数,howmany=0为不删除,改插入,插入index-1位置;...itemn为加入的参数若干,非纯函数,输出改变

  

var xs = [1,2,3,4,5];

// 不纯的
xs.splice(0,3);
//=> [1,2,3]

xs.splice(0,3);
//=> [4,5]

xs.splice(0,3);
//=> []

 

  纯函数:arr.slice(start,end) 提取,返回子arr,内容是从 start 处到 end-1,参数可负,原arr不变,纯函数输出不变

  Array.prototype.slice.apply(arguments) 类数组转数组 e.g.call

  arr.indexOf

  arr.find(callback) 查找满足条件的第一个值

  arr.findIndex(callback)

字符串处理:

  str.substring(start,end) 提取,返回子str,内容是从 start 处到 end-1,if (start<0) start=0,原str不变

  str.split() 分割,返回数组arr,若需要进一步split,注意:分割后为数组,故用for循环split

  str.parse() 转成json,注意:字符串中的属性要严格加上引号

  str.substr(start,length) 返回子str,注意:不建议使用

  字符串的部分修改可以使用replace 或者拼接

  str.slice

  str.indexOf

  str.replace 正则替换

5.underscore对象处理:

  underscore 待整理

  if ( 'a' in obj ) 判断对象 (json)obj 中是否有 a,注意 'a' 的 '',同样 obj 可以替换为 arr,但此时只能寻找下标 0,1,2...

json处理:

  json.stringify() 转成str

  json 转 url string:for in 遍历,push( = ) 存入数组,join('&') 转成 str,补套接字

  json.parse() 将字符串转换成 json

  遍历用 for in 后存入 push 数组

 

7.switch(true){case 80<n:document.write('优秀');break;}//当表达式为比较时,参数为布尔值。

8.Math.floor/Math.ceil/Math.round//要上下兼顾建议floor,使用Math.floor(Math.random()*(max-min+1)+min)

9.页面所获取的内容都是字符串,eg:typeof getElementById(ID).value

10.URL-encode处理避免读取错误请求 url:    encodeURLComponent()     

e.g.     encodeURLComponent("MTAuMTA4LjUyLjM2O2FkbWluO2ExMjM0NTY3OzgwMDA=")   //MTAuMTA4LjUyLjM2O2FkbWluO2ExMjM0NTY3OzgwMDA%3D

11.<button onclick='func(event)'></button>//event必须通过实际参数形式传递给函数func(e),考虑是否需要全局window

{alert(e.target.value);}

12.javascript 是单线程的,但浏览器内部不是单线程的。你的一些 I/O 操作,定时器的计时和事件监听(click,keydown...)等都是由浏览器提供的其他线程来完成的。

改变 this 指向:将 this 添加到指定环境中,若环境为 null,则指向 window。

  .call(环境,参数1,参数2)

  .apply(环境,[参数1,参数2])

  .bind(环境,参数1,参数2...)

  总结:call和apply都是改变上下文中的this并立即执行这个函数,bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加。

  e.g.

var a = {
    user:"追梦子",
    fn:function(e,d,f){
        console.log(this.user); //追梦子
        console.log(e,d,f); //10 1 2
    }
}
var b = a.fn;
var c = b.bind(a,10); //或者 var d = b.bind(a,10,1,2);  或者 var e = b.bind(a)   
c(1,2);

13.动态创建的dom元素

  在此基础上添加监听事件,需要全局方法 <dom onclick='window.fn()' /> 或查询相关资料。

14.禁止使用 遍历节点添加事件绑定

  解决方法:父级监听事件委托/代理 addEventListener('events', fn, false);

15.try catch 异步编程中

  try 代码块中避免使用赋值逻辑,并结合类型检查 typeof

  朴灵曾提到:异步编程的难点之一是异常处理,书中描述 "尝试对异步方法进行try/catch操作只能捕获当次事件循环内的异常,对call back执行时抛出的异常将无能为力"。

 16.闭包的属性方法

var arr = [];
for(var i = 0; i < 2; i++){
    (arr[i] = function self(){
        console.log(self.x);
    }).x = i;
};
arr[1](); // 1

 17.判断变量的类型

Object.prototype.toString.call(1) //"[object Number]"

 18.apply, call  不过是改变函数上下文

let obj = {}
fn(a, b)
fn.apply(obj, arr)
// 解析:
// obj 为加入的对象,该参数表示需要变更的执行大小文,说白了,就是改变原本fn的指向,即this。
// arr:Array 即传递给fn的参数,['A', 'B'] 对应 fn的arguments


fn.call(obj, 'A','B')

所以当你需要某个函数中的属性和方法,只需要在:目标函数里 { 需要的函数.call(this) } 即可。

fn.call() // or apply 会使函数立即执行

bind 与 call 有点类似,不同点在于

var func1 = fn.bind(obj);
func1();

// 解析:绑定obj后不会立即执行函数,而是返回一个改变了上下文 this 后的新函数。原函数fn的this依旧为window
// call 是把第二个及以后的参数作为 func 方法的实参传进去,而 func1 方法的实参实则是在 bind 中参数的基础上再往后排

自己实现bind

if (!Function.prototype.bind) {
        Function.prototype.bind = function () {
            var self = this,                        // 保存原函数
                context = [].shift.call(arguments), // 保存需要绑定的this上下文
                args = [].slice.call(arguments);    // 剩余的参数转为数组
            return function () {                    // 返回一个新函数
                self.apply(context,[].concat.call(args, [].slice.call(arguments)));
            }
        }
    }

apply, call, bind 请参考 https://github.com/lin-xin/blog/issues/7

apply, call, bind 涉及的闭包与 js 执行上下文相关,遇到 执行 函数 (...实参) ,即创建一个新的执行上下文。同时 js 引擎将该上下文添加到调用堆栈。当调用结束后从调用堆栈中删除。

19.元素置换[乱起的名]

let arr = [1, 3, 2];
let val = arr[0];
arr[0] = arr [1];
arr[1] = val
console.log(arr); // [3, 1, 2]

// 引申快捷操作:
// 外面数组表示对应位置互相置换
// 同时改变里面成员的值
[arr[0], arr[1]] = [arr[1], arr[0]]

 20.深拷贝:完全拷贝一个新对象,修改时原对象不再受到任何影响。 JSON.parse(JSON.stringify(obj))

21.fs.readFile 读文件结果为buffer,buffer.toString()

22.让代码继续下去

try{ 
    // 捕获错误
}catch(e){
    // 不放内容,直接运行下去
}


// 或者reject catch
await Promise.reject('出错内容').catch(err => {
   console.log(err) 
})

 实例:确保每个异步都能正常进行下去

async function fn() {
  try{
        let f1 = await readFile('data/a.txt')  
        let f2 = await readFile('data/b.txt')  
  }catch(e){}  
  
  console.log(f1.toString())
  console.log(f2.toString())
}    

 23.类静态属性

class Test {
    static fn () {}          
}

Test.fn()

 24.import * as name语法导入所有导出接口,即导入模块整体

 25.text-align: justify; // 文字两端对齐

 26.for of 解决 forEach 无法 return 结束的问题

for (let [idx, val] of delayList.entries()) {
}

 27.异步生成数组,同步直接在for循环里处理逻辑即可

(function next(i, len, callback) {
    if (i < len) {
        async(arr[i], function (value) {
            arr[i] = value
            next(i+1, len, callback)
        })
    } else {
        callback()
    }
} (0, arr.length, function () {
    // all array items have processed
}))

 28.同步执行,并根据最终数组进行后续处理

(function next2(i, len, count, callback) {
    for (; i < len; i++) {
        (function (i) {
            async(arr[i], function (value) {
                arr[i] = value
                if (++count === len) {
                    callback()
                }
            })
        }(i))
    }
} (0, arr.length, 0 ,function () {}))

 29.事件委托(兼容)

let oUl = document.querySelector('ul-class')
oUl.onmouseover = function (e) {
    var e = e || window.event;
    var oLi  = e.srcElement || e.target;
    if (oLi.nodeName.toLowerCase() === 'li') {
        oLi.style.background = 'red';
    }
}   

 30.async 与 promise.all

async function A1() {
let res = await Promise.all([cPromise, cPromise]);   // 简单但灵活性降低了,只有都成功或者都失败两种情况。
console.log(res)
}

// 推荐
async function A2() {
let res = [];
let reqs = [cPromise(), cPromise()]; // 注意这里其实已经开始执行异步;
for (let i=0; i<reqs; i++) {  // 基本没有消耗
   res[i] = await reqs[i]
}
console.log(res)
}

async 的错误处理

function createPromise (needCatch:boolean) {
    let p = new Promise((resolve, reject) => {
         reject(10);
    });
    return needCatch ? p.catch(err => err) : p;  // 提前包装捕获错误或者在 async 函数中使用 try.catch
}

 31.使用 Boolean 构造函数过滤数组中的所有假值

const compact = arr => arr.filter(Boolean);

compact([0, 1, false, 2, '', 3, 'a', 'e'*23, NaN, 's', 34]);

// [1, 2, 3, 'a', 's', 34]

32.取整 | 0

33.判断奇偶 !!(num & 1);  奇数为true, 偶数为 false

34.强制参数

mandatory = () => {
    throw new Error('Missing parameter !');
}

foo = (bar = mandatory()) => {
    return bar;
}

35.惰性载入函数,首次判断后覆写原函数,之后结果统一用复写的

function foo() {
    a !==b ? console.log('aaa') : console.log('bbb')
}

// 覆写后,当判断分支足够多时,节约的资源还是很客观的
function newFoo () {
    if (a !== b) {
        foo = () => console.log('aaa')
    } else {
        foo = () => console.log('bbb')
    }
    return foo();  
}

36.一次性函数

var sca = function () {
    console.log('msg')  // 只执行一次,之后重新覆写
    sca = function () {
        console.log('foo')
    }  
}

37.字符串比较时间先后:字符串是从左到右比较每个字符的charCode的,注意:时间形式需要补0;

console.log('2014-08-08' < '2014-09-09'); // true
console.log('21:00' < '09:10') // false
// 数字补0
const addZero = (num, len = 2) => (`0${num}`).slice(-len)

38.精确到指定位数的小数(四舍五入)

const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`)

round(1.235, 2) // 1.35
round(1.345, 1) // 1.3

39.统计数组中相同项的个数

var cars = ['BMW', 'Benz', 'Benz', 'Tesla'];
var carsObj = cars.reduce(function (obj, name) {
   obj[name] = obj[name] ? ++ obj[name] : 1;
   return obj  
}, {});
carsObj;

40.将数组平铺到指定深度

const flatten = (arr, depth = 1) {
    depth !==1 
    ? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flatten(v, depth -1) : v), [])  
    : arr.reduce((a, v) => a.concat(v), [])  
}

flatten([1, [2], 3, 4]);    // [1, 2, 3, 4]
flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]

41.数组的对象解构,可以方便地获取数组的第 n 个值

const csvFileLine = '1997,John Doe,US,john@doc.com,New York';
const {2:country, 4:state} = csvFileLine.split(',');

// country      US
// state          New York

42.采用解构删除不必要的属性

let {_internal, tooBig, ...cleanObject} = {el1: '1', _internal: 'secret', tooBig: {}, el2: '2', el3: '3'};

console.log(cleanObject);  // {el1: '1', el2: '2', el3: '3'}

 43.在函数参数中解构嵌套对象

var car = {
    model: 'bmw 2018',
    engine: {
        v6: true,
        vin: 12345
    }
}
const modelAndVin = ({model, engine: {vin}}) => {
    console.log(`model: ${model} vin: ${vin}`)
}
modelAndVin(car)

44.通用表单验证

const schema = {
    first: {required: true},
    last: {required: true}
}

const validate = (schema, values) => {
    for (field in schema) {
        if (schema[field].required) {
            if (!values[field]) return false
        }
    }
    return true
}
console.log(validate(schema, {firstL 'Bruce'}));  // false
console.log(validate, {first: 'Bruce', last: 'Wayne'});   // true

 45.两端对齐,数字字母不分割

.text {
  text-align: justify;
  word-break: normal;
}

 46.sort((a, b) => a-b) 为什么是升序,可以简单将 a,b 理解为 unicode,b 比 a 大,a - b 为升序

 47.animation 不按预期停止动画,使用 forwards 解决,意为动画到 100 % 就停止,而不恢复到初始

.fr { animation: name 2s ease-in forwards }

 48. 静态导入导出

export const a = 1
export const b = 2
const c = 3
export default c

import c, {a, b} from __dirname

import * as cur from __dirname // { a:1, b: 2, default: 3 }

 49.web worker 只能加载网络同源 url 或者字符串 js

class webWorker {
  /**
   * @description: webworker的简单封装
   * @param {String} data js的url/script的id或class
   * @param {Object} type 默认值给出,同页面的web worker传个’worker‘即可
   * @return: WebWorker 对象
   */
  constructor(data, type = "url") {
    this.worker = null;
    this.workerInit(data, type);
  }
  workerInit(data, type) {
    if (type === "url") {
      // 默认是以url脚本形式的worker线程
      // 此时的data应该是一个url链接
      this.worker = new Worker(data);
    } else {
      // 以字符串形式创建worker线程,把代码字符串,转成二进制对象,生成 URL,加载URL
      const blob = new Blob([data]);
      const url = window.URL.createObjectURL(blob);
      this.worker = new Worker(url); // 加载
    }
  }
  /**
   * @description: 给worker线程发送消息
   * @param {*} data 要发送的数据
   */
  postMessage(data) {
    return this.worker.postMessage(data);
  }
  /**
   * @description: worker线程发送给主进程的数据
   * @param {Function} fn 把数据通过回调的形式传出去
   */
  onmessage(fn) {
    this.worker.onmessage = msg => {
      return fn(msg.data);
    };
  }
  // 主线程关闭worker线程
  closeWorker() {
    return this.worker.terminate();
  }
  /**
   * @description: 主线程监听worker线程的错误信息
   * @param {Function} fn 错误信息回调
   */
  errMsg(fn) {
    this.worker.onerror = e => {
      return fn(e);
    };
  }
}

const data = `
      // worker线程加载脚本 TODO: Worker 线程无法读取本地文件,加载的脚本必须来自网络
      // importScripts('hello1.js', 'http~.js');
      
      // 监听主线程传过来的信息
      self.onmessage = e => {
        console.log('主线程传来的信息:', e.data);
        // do something
      };
      
      // 发送信息给主线程
      self.postMessage('来自worker线程');
      
      // 关闭worker线程
      function closeSon() {
        return self.close();
      }`;

const worker = new webWorker(data, "script");
worker.onmessage(data => {
  console.log("父进程接收的数据:", data);
});
worker.postMessage("主进程传给worker线程");
worker.errMsg(msg => {
  console.log("worker线程报错:", msg);
});

 

posted @ 2019-07-13 11:45  blackatall  阅读(365)  评论(0编辑  收藏  举报