Git Product home page Git Product logo

review-javascript's People

Contributors

caraws avatar

Watchers

 avatar

review-javascript's Issues

Bitwise

位运算符

在C或者其他语言数值的运算其实都是先将数值转换为二进制在做运算的,
而位运算符就是直接进行二进制运算, 因此速度会非常快. 但是对于JavaScript
来说, 执行环境一般接触不到硬件, 所以性能完全不能和其他语言相比. 不过作为
了解还是需要的, 只对较为常见的位运算符作记录.

位运算 NOT

位运算 NOT 由 ( ~ ) 符号表示, 其实就是对数值求负之后再减一, 如:

let num = 10;
let num2 = ~num;

// ~num 效果同下
num2 = -num - 1;

console.log(num2); // -11

左位移运算

左位移运算由 ( << ) 符号表示. 将数值的所有位向左移动指定数量.例如:
左移一位乘2, 左移2位乘4, 以此类推.

let num = 2;
let num2 = num << 2;

// 效果同下
 num2 = num * 4;

console.log(num2); // 8

有符号右移运算

有符号右移运算符由 ( >> ) 符号表示, 将数值的所有为向右移动指定位数,
同时保留该数的符号 (正好或者负号) . 有符号右移运算符跟左位移运算符正好
相反.

let num = 12;
let num2 = num >> 2;

// 效果同下
num2 = num / 4;

console.log(num2) // 3

无符号右位移运算符

无符号运算符由 ( >>> ) 符号表示, 对于正数无符号右位移运算符跟无符号右位移
运算符规则相同; 负数时会出现无限大的数值, 所以决定使用无符号右位移运算符
时一定要小心.

Base64 转Blob

Base64 转 Blob 类型

var arr = base64.split(','), mime = arr[0].match(/:(.*?);/)[1],
               bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
                while (n--) {
                    // charCodeAt() 方法可返回指定位置的字符的 Unicode 编码
                    u8arr[n] = bstr.charCodeAt(n);
                }
                // 'application/octet-binary' (默认值)
                let blob = new Blob([u8arr], { type: mime })

Base64 的编码码和解码

使用atob 和 btoa 方法.

  • atob() 解码
atob("amF2YXNjcmlwdA==")
// 解码结果 "javascript"
  • btoa() 编码
window.btoa(javascript)
// 转码结果 "amF2YXNjcmlwdA=="

以上两种方法对于中文是有局限性的, 解决如下:

var str = "China,**";

// 先用 encodeURI() 编码
window.btoa(window.encodeURIComponent(str))
// "Q2hpbmElRUYlQkMlOEMlRTQlQjglQUQlRTUlOUIlQkQ="

// atob 解码 Base64 再用 decodeURI() 解码
window.decodeURIComponent(window.atob('Q2hpbmElRUYlQkMlOEMlRTQlQjglQUQlRTUlOUIlQkQ='))
// "China,**"

17/9/4

Quick Sort

Quick Sort (快排法)

快速排序的实现,,参考资料阮一峰

思路

快排法的**, 分为以下三步

  1. 在数据集中, 选择任意一个数据作为参照物(一般取中间位置的元素)。
  2. 所有小于参照物的元素都放在左边,大于参照物的元素都放在右边。
  3. 对左右两边的子集递归, 至到排序完成。

例子

  • 非原地快速排序
var array = [11, 65, 23, 108, 99, 11, 55, 11, 33, 100, 108, 100];

console.time('快排');
const quickSort = array => {
    // 数组只剩一个元素时停止
    if (array.length <= 1) return array;
    // 取参照物
    let pivotIndex = Math.floor(array.length / 2),
        // 这里用splice删除参照物避免重复循环
        pivot = array.splice(pivotIndex, 1),
        leftArr = [],
        rightArr = [];
    // 分区
    for (let i = 0; i < array.length; i++) {
        if (array[i] < pivot) {
            leftArr.push(array[i]);
        } else {
            rightArr.push(array[i]);
        }
    }
    return quickSort(leftArr).concat(pivot, quickSort(rightArr));
}
console.log(quickSort(array)); // [ 11, 11, 11, 23, 33, 55, 65, 99, 100, 100, 108, 108 ]

console.timeEnd('快排'); // 4ms 左右
  • 原地快速排序
console.time('快排2');
// 互换
const swap = (items, firstIndex, secondIndex) => {
    let temp = items[firstIndex];
    items[firstIndex] = items[secondIndex];
    items[secondIndex] = temp;
}
// 分区
const partition = (items, left, right) => {
    let pivot = items[Math.floor((right + left) / 2)],
        i = left,
        j = right;

    while (i <= j) {
        while (items[i] < pivot) {
            i++;
        }
        while (items[j] > pivot) {
            j--;
        }
        if (i <= j) {
            swap(items, i, j);
            i++;
            j--;
        }
    }
    return i;
}
// 排序
const quickSortTwo = (items, left, right) => {
    let index;
    if (items.length > 1) {
        left = typeof left != "number" ? 0 : left;
        right = typeof right != "number" ? items.length - 1 : right;

        index = partition(items, left, right);

        if (left < index - 1) {
            quickSortTwo(items, left, index - 1);
        }

        if (index < right) {
            quickSortTwo(items, index, right);
        }
    }
    return items;
}

console.log(quickSortTwo(array));
console.timeEnd('快排2');
  • 原生sort
console.time('原生');
array.sort((a, b) => {
    if (a > b) return 1
    else if (a < b) return -1
    else return 0
});
console.log(array);
// 5ms 左右
console.timeEnd('原生')

两种方法, 当数组达到1W时差距就比较大了,原生需要17ms左右,原地快排需要13ms左右,而非原地快排则需要88ms左右。

17/9/7

Modules

模块

使用函数和闭包来构造模块. 模块是一个提供接口却隐藏状态与现实的函数或对象.

通过模块可以摒弃全局变量的使用, 模块模式的一般形式是: 一个定义私有变量和函数的函数;
利用闭包创建可以访问私有变量和函数的特权函数. -----<JavaScript语言精粹>

const serial_maker = _ => {
	// 私有变量
	let prefix = '';
	let num = 0;

	return {
		// 特权方法
		set_prefix: str => {
			prefix = String(str);
		},
		set_num: n => {
			num = +n;
		},
		get_sum: _ => {
			let result = prefix + num;
			num++;
			return result;
		}
	}
}

let seqer = serial_maker();
seqer.set_prefix('Hi');
seqer.set_num(0101);

console.log(seqer.get_sum()) // 'Hi0101'

CommonJs 与 AMD

因为有了模块的概念, 所以我们能将很多重复性的代码封装成一个模块, 想用什么
功能就加载什么模块, 也能更方便是使用别人的代码. 但是这样就会要求大家都用
同样的方式封装模块, 所以就有了 CommonJs 和 AMD 来规范大家的写法.

  • CommonJs
    Node.js的模块就是参照 CommonJs 来实现的, 在服务器端是一定会用到模块的. CommonJs
    是同步加载, 也就是说当引入一个模块必须等待该模块加载完成之后, 才会执行接下来的代码.
    对于服务器来说所有的模块都放在本地, 所以等待的时间很短; 但对于浏览器来说, 所有的模块
    都放在服务器, 所以等待的时间完全取决于网速, 就很容易出现假死的状态.
var math = require('math');

math.add(2, 3);
  • AMD
    AMD是"Asynchronous Module Definition"的缩写, 意思就是"异步模块定义". 它就是采用异步
    加载, 因此模块的加载并不影响后面的语句执行. 将所有依赖于这个模块的语句都放在一个定义的回调
    函数中执行, 这样等待模块加载完成之后就会去执行这个回调函数.
require([module], callback);

require(['module'], module => {
	module.increment(1, 2)
}) 

export / export default

在JavaScript ES6中,export与export default均可用于导出常量/函数/文件/模块等,
以便在其它文件或模块中通过import将其导入使用.

  • export
    export 可以导出多个
// types.js
export const foo = 'foo';

export const fn = n => n+1;

// 在 index.html 引入
import {foo, fn} from 'types.js'
  • export default
    只能导出一个
// types.js
export default const foo = 'foo';

// 在 index.html 引入
import foo from 'types.js'
// 等价于
import {default as foo} from 'types.js'
  • 17/9/15 *

CSS 盒模型

CSS 盒模型

CSS 盒模型 (Box Model), 包含的要素分别为: content/padding/border/margin.

标准盒模型 & 怪异盒模型

盒模型分为W3C的标准盒模型和IE的标准盒模型.

  • 标准盒模型
    content + padding+ border + margin 标准盒模型的 content 是不包含其他部分的, 如下图:
    W3C-BOX

  • IE标准盒模型
    content(padding + border) + margin 而IE标准盒模型的 content 已经包含padding和border的值, 如下图:
    IE-BOX

在文档顶部声明 DOCTYPE 就是为了让浏览器使用 W3C标准盒模型, 但是在 IE5/ IE6 下依然是 IE 标准盒模型. 当然通过box-sizing属性可以在两者之间转换.

常见问题

  1. 两个垂直方向相邻的块级元素相遇时, 外边距会合并且取值两者较大值的 margin 作为外边距.
    解决方案: *{ margin: 0; padding: 0 }

  2. margin 出轨...
    当父元素没有 border 边框时, 第一个子元素添加 margin-top 会超出父元素, 相同最后一个子元素添加 margin-bottom 也同样会超出父元素, 如下图:

  • 第一个子元素添加 margin-top
    marginTop

  • 最后一个子元素添加 margin-bottom
    marginBottom

  • 前两者同时存在时, 父元素添加 border
    marginBottom

解决方案有四种:

  1. 给父元素添加 border.
  1. 给父元素添加 padding.
  1. 给父元素添加 overflow: hidden.
  1. 给父元素添加伪类. (最佳)
    .parent { content: ''; display: table; }

2017-8-15

JavaScript关于运算符的小技巧

1. 使用 !! 操作符转换布尔值

  • 用于检查一个变量是否存在或者是有效值, 对变量使用 !!variable 来验证,
    只要变量的值为: 0, null, undefined, NaN都将返回 false, 反之返回 true. 如:
 class Foo {
    constructor ( count ) {
        this.cash = count;
        this.myCash = !!count;
    }
}
var emptyFoo = new Foo(0);
console.log(foo.cash); // 0
console.log(foo.myCash); // false

var foo = new Foo(100);
console.log(foo.cash); // 100
console.log(foo.myCash); // true

2. 使用 + 将字符串转换为数字

  • 只适合将字符串数据转换为数字, 给后台传数据的时候经常用到,
    如果不是字符串数据会返回 NaN.
var toNumber = strNumber => {
    return +strNumber;
}
console.log( toNumber("123") ); // 123
console.log( toNumber(" abc")); // NaN

// Date也可以使用
console.log( +new Date() ); // 返回时间戳

3. 并符条件

  • 经常用到这样的条件判断.
if (isConcat) {
    Login()
}

可以简写成这样 isConact && Login()

4. 获取数组中的最后一个元素

  • ` Array.prototype.slice (begin, end)` 经常用这样的方式来截取数组的元素,
    如果不设置 end 的值, 那么默认会将数组的长度作为 end 值.
    如果将负数作为参数的 begin 值, 就可以获取数组的最后一个元素.
var arr = [1,2,3,4,5];
console.log( arr.slice(-1) ); // [5]
conosle.log( arr.slice(-2) ); // [4,5]
以此类推

5. 截断数组

  • 用来锁定数组的长度, 删除数组中的一些元素. 比如数组一共有10个元素,
    但我只需要前5个元素, 就可以通过 array.length = 5 来截断数组, 如:
var arr = [1,2,3,4,5];
console.log( arr.length); // 5
arr.length = 3;
console.log( arr.length ); // 3
console.log( arr ); // [1,2,3]

6. 将NodeList转换为数组

  • 如果通过 doucment.querySelectorAll('p') 获取元素, 它返回的是一个DOM元素的
    数组 ( NodeList ) 对象, 但是这个数组不具有数组的功能,
    比如 push() / sort() 等. 这就需要将这个 NodeList 转换为真正的数组.
    可以使用 [].slice.call( NodeList ) 来实现. 如:
var els = document.querySelectorAll( 'p' );
[].slice.call( els );
OR:
var arrElement = Array.from( els );
ES6:
var arr = [...els]

7. 数组元素重排

var list = [1,2,3];
console.log(list.sort(()=>{ Math.random() - 0.5}))

17/6/14

迭代数组对象中的数组

迭代数组对象中的数组

有时候需要遍历后端返回的数据是数组中的数组, 可能是无限嵌套的情况.
比如: 查询省市区的情况, 需要判断当前选中的城市是否有子级.

if ( child == null || child.length == 0 ){
        // 省市区只有三级
        // area-code 是当前选中的地区编码
	var length = area-code.length / 2;
       // 现有城市数组
	var array = areaList;
	for ( var i = 0 ; i < length ; i++ ){
		for ( el of array ){
			if ( el.area-code == area-code.substr(i*2,2) ){
				if ( i == length - 1 ){
					delete el.children
					return;
				}else{
					array = el.children;
					break;
				}
			}
		}
	}
}

预览监控摄像头

预览监控摄像头

在预览摄像头监控画面时, 用socket发送RTSP实时视频流. 在浏览器中接收到是一堆bytes, 所以需要转化为blob类型或者base64给canvas渲染出来.

  1. Node端
    当时用的是一个个人项目rtsp-ffmpeg 链接, 有空的话可以看看WebRTC
  • 安装FFMPEG FFMPEG下载
  • 解压后, 在C盘根目录下创建文件夹ffmpeg, 将解压文件放入
  • 设置环境变量, windows下在我的电脑 -> 属性 -> 高级系统设置 -> 环境变量 -> 系统变量 -> 新增
    在刚刚ffmpeg的路径上具体到文件夹中的bin文件夹
  • 测试, 在命令行中输入ffmpeg -version 出现版本号啥的就安装成功 ( 如果不行的话, ffmpeg的文件名换为FFMPEG就好, 不知道为啥就是要改下文件名; 或者重启 )
  1. 利用socket.io向浏览器发送视频数据
    关键代码:
 var rtsp = require('rtsp-ffmpeg');
 // 推流
 var uri = 'rtsp://accout:password@ip:port/h264/ch1/main/av_stream',
     stream = new rtsp.FFMpeg({
         input: uri,
         rate: 10,
         resolution: '320x240',
         quality: 3
     });

 var cameraInfo = {}
 io.on('connection', socket => {
     console.log('connection')
     var pipeStream = function(data) {
         socket.emit('data', data);
     };
     stream.on('data', pipeStream);
     socket.on('URI', data => {
         console.log(data);
         cameraInfo.cameraName = data.cameraName;
         cameraInfo.groupName = data.groupName;
         uri = `rtsp://${data.userName}:${data.passWord}@${data.ip}:${data.RTSP}/h264/ch1/main/av_stream`;
         stream.input = uri;
         stream.restart();
         socket.emit('CameraInfo', cameraInfo);
     })
     socket.on('disconnect', function() {
         stream.removeListener('data', pipeStream);
     });
 })

中间将Node.js托管到IIS服务器上时会出现跨域的报错, 可能是和后端连接时端口被占, 具体看IIS报什么错. 如果IIS没报错, 还是有跨域的错重装一次socket.io基本可以解决.

如果用canvas预览摄像头还是有花屏的情况, 可以将码流切换为子码流rtsp://accout:password@ip:port/h264/ch1/sub/av_stream

  1. 浏览器
    基于Vue.js, 先引入socket.io并建立连接, 然后对视频流数据做处理(展示时不要用img标签, 掉帧比较严重).

关键代码:

var bytes = new Uint8Array(data);
					
var blob = new Blob([bytes], {type: 'application/octet-binary'});
                
var url = URL.createObjectURL(blob);
                
var img = new Image;
                
var ctx = this.canvas.getContext("2d");
    img.width = img.width * 0.5;
    img.height = img.height * 0.5;
    img.onload = function() {
         URL.revokeObjectURL(url);
         ctx.drawImage(img, 0, 0,720,560);
    };    
img.src = url;

2017/7/26

JavaScript深浅拷贝

JavaScript 深浅拷贝

浅拷贝

浅拷贝只能拷贝顶层属性基本数据类型, 也就是如果父对象的属性是一个对象或数组, 那么子对象获取到的只是一个内存地址而不是一个真正的对象, 所以一旦修改父对象也会跟着被篡改.

    function shallowCopy ( parent ) {
        let o = {};
        for (let i in parent) {
             o[i] = parent[i]
        }
        return o
    }

深拷贝

深拷贝也就是能够实现数组和对象拷贝, 深拷贝与浅拷贝对比, 深拷贝会在堆区开辟新的一块来储存新的对象. 两个对象对应的是两个不同的内存地址, 所以修改其中一个对象的属性并不会影响到另一个对象的属性. 实现深拷贝也有两种方式: 一种是递归/ 一种是JSON.

  1. 递归
    function deepCopy ( parent, child = {} ) {
        for ( let i in parent ) {
            if ( typeof parent[i] === 'object' ) {
                child[i] = ( parent[i].constructor == Array ) ? [] : {};
                deepCopy( parent[i], child[i])
             } else {
                 child[i] = parent[i]
             }
        }
    }
  1. JSON解析
    var o = {
        age: '18',
        friends: ['老张', '老王'],
        job: {
           main: '睡觉',
           sub: '躺着'
        }
    };
    var result = JSON.parse( JSON.stringify(o));
    result.name = 'cara';
    result.friends.push('老李');
    console.dir(o);
    console.dir(result)

通过JSON解析的方式不懂他的套路....

2017-8-15 18:38

Inheritance

继承

在那些基于类的语言, 继承是一种代码重用的形式, 如果一个新的类与一个已存
在的类拥有大部分相同的功能, 那么就只需要说明两者之间的区别即可. 但是
JavaScript 并没有类的概念, 但是有很多代码重用的模式, 它可以模拟类的
模式, 也可以支持其他的模式.

伪类

在 C++ 和 Java中都是用 new 命令来生成示实例, 在使用 new 命令时都会调用类的
构造函数(constructor), 因此 Brendan Eich ( JavaScript 作者)将 new 引入了 JavaScript,
从原型对象上生成一个实例对象. 因为 js 没有类, 所以在 new 命令后面跟的是构造函数,
而不是像 Java 一样跟的是类. 简单的来说就是通过构造器生产对象.

// 先扩展一个方法, 懒得每次打prototype
// 这个不是必须的
Function.prototype.method = (name, fn) => {
	this.prototype[name] = fn;
	return this	
}

// 语言精粹里的例子 (其实这一步就是在模仿 new 的实现)
Function.method('new', _ => {

	// 创建一个新对象, 它继承构造器函数的原型对象
	let that = Object.create(this.prototype);

	// 调用构造器函数, 将 this 绑定到新对象上
	let other = this.apply(that, arguments);

	return (typeof other === 'object' && other) || that
})

// 现在定义一个构造器
let Bar = name => {
	this.name = name;
}

// 扩展这个构造函数的原型
Bar.prototype.get_name = _ => this.name;
Bar.prototype.say = _ => this.saying || '';

// 然后构造一个实例
let myBar = new Bar('妲己');
console.log(myBar.get_name()) // 妲己

/**
 *  掩盖掉丑陋的 prototype
 */

// 借助一个辅助函数
Function.method('inherit', parent => {
	this.prototype = new parent();
	return this
})

// 重新定义一个构造函数
// 去继承上面的 Bar
let Foo = name => {
	this.saying = 'wow';
}
// 这里 inherit 和 method 都直接返回 this
// 所以可以采用联级
.inherit(Bar)
.method('noise', _ => {
	return this.name + this.say()
})

伪类模式在通过new 命令生产对象时, 会产生内存浪费. 如上面的例子, Foo 构造函数
就回去重复构造器 Bar 已经完成的工作.

原型

在一个纯粹的原型模式中, 将摒弃类专注于对象. 基于原型的继承相比于类的
继承在概念上更为简单: 一个新对象可以继承一个旧对象的属性. 通过构造一个有用
的对象开始, 接着可以构造出更多和这个对象相似的对象. ----<JavaScript语言精粹>

// 先构造一个基础对象
const baseObject = {
	name: 'base',
	get_name: _ => this.name
}

// 接下来构造定制化的对象
let myObj = Object.create(baseObject);
myObj.name = 'wow';
myObj.saying = 'Hi';
myObj.purr = n => {
	let str = '';
	for (let i = 0; i < n; i++) {
		if (s) {
			str += 'hello'
		}
		str += 'world'
	}
	return str
}

这是一种'差异化继承', 通过制定一个新的对象, 指明它与基本对象的不同.

函数化

以上两种继承模式都没有实现私有化, 也就是说所有的变量和方法都是公开的, 所以就
可以开始运用模块模式. 这个函数主要分为四个步骤:

  1. 创建一个新的对象

  2. 定义私有属性.

  3. 给这个新对象扩充特权函数 (暴露接口)

  4. 返回这个对象

// spec 对象包含构造器所需要的所有信息
// my 对象允许其他构造器分享他们的私有属性
// 以便在我们的构造器中使用
let constructor = (spec, my) => {
	let that = {}; // 私有实例变量

	let my = my || {};
	
	// 扩展共享的变量和方法
	...

	that = 一个新对象

	// 给 that 添加特权方法 
	...

	// 返回这个对象
	return that
}

语言精粹里的例子

  1. 构造器
cosnt mammal = spec => {
	let that = {};

	that.get_name = _ => spec.name;
	that.says = _ => spec.saying || '';

	return that
}

let myMammal = mammal({name: 'Herb'});
  1. 另一个构造器
let cat = spec =>{
	spec.saying = spec.saying || 'meow';
	// 继承
	let that = mammal(spec);
	
	that.purr = n => {
		let i, s = '';

		for (i = 0; i < n; i++) {
			if (s) {
				s += '-';	
			}
			s += 'r';
		}
		return s
	};
	that.get_name = _ => {
		return that.says() + ' ' + spec.name + ' ' + that.says();
	}

	return that
}

let myCat = car({name: 'Henrietta'});

超类

以上函数化的方式还不能够调用父类的方法并向父类方法传递参数. 以下是测试代码
语言精粹的例子的基础上稍作改动, 便于自己理解:

// 构造器
const mammal = spec => {
	let that = {};

	that.get_name = _ => spec.name;
	that.says = _ => spec.saying || 'Hi';

	return that
}

let myMammal = mammal({name: 'Cara'});

console.log(myMammal.says()) // 'Hi'


// 构造器2
const cat = spec => {
	spec.saying = spec.saying || 'meow';

	// 此时 that 已经包含: get_name 和 says 方法
	let that = mammal(spec);

	that.purr = n => {
		let str = '';

		for (let i = 0; i < n; i++) {
			if (str) {
				str += '-';
			}
			str += 'r';
		}
		return str
	};
	that.get_name = n => {
		return n || "i dont't have name"
	};

	return that
}

let myCat = cat({name: 'Henrietta'});

// i dont't have name
console.log(myCat.get_name())

// 这个时候 cat 还不能访问父类方法的能力
// 所以超类 super 还是有必要的

// 先扩展两个方法
// 这个方法不能用箭头函数来定义, 否则 this 指向的window
// 这里 this 需要的是被调用的对象
Function.prototype.method =  function (name, fn) {
	this.prototype[name] = fn;
	return this
}

// 定义调用父类的函数
Object.method('superior', function (name) {
	var that = this,
        method = that[name];
    return n => {
    	// this cat function
    	console.log(n)
        return method.call(that, n);
    };
})

// 来试试调用父类
const coolCat = spec => {
	let that = cat(spec);
	let	super_get_name = that.superior('get_name');

	// n 给父类方法传参
	that.get_name = n => {
        return 'like ' + super_get_name.call(this, n) + ' baby';
    };

	return that
}

let myCoolCat = coolCat({name: 'Bix', saying: 'Hi'});

let name = myCoolCat.get_name('this cat function');

console.log(name) // like this cat function baby

最后随便提一下

箭头函数的几个使用注意点:

  1. 函数体内的 this 对象, 就是定义时所在的对象, 而不是使用时所在的对象.

  2. 不可以当作构造函数, 也就是说, 不可以使用new命令, 否则会抛出一个错误.
    因为箭头函数没有自己的 this, 而是继承外层函数的this.

  3. 不可以使用 arguments 对象, 该对象在函数体内不存在.

  4. 不可以使用 yield 命令, 因此箭头函数不能用作Generator函数.

  • 17/9/15 *

CSS 水平垂直居中大整合

# CSS 垂直水平居中大整合

在平时的布局中常常会用到的垂直水平居中. 下面就来总结几种垂直
水平居中的方法.

1. 绝对定位水平垂直居中

给元素设置绝对定位, 其父级元素为body或者指定的相对定位元素.
它的缺点是必须设置宽度值或者高度值; 优点是兼容性挺好, 代码也不
多, 不过听说在 windows phone 上不起作用.

<div class='wrapper'>
	<div class='absolute-center'>我是绝对定位<div>
</div>
.wrapper{
	width: 100%;
	height: 200px;
	position: relative;
	border: thin solid black;
}
.absolute-center{
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	margin: auto;
	background: deepskyblue;
	height: 100px;
	line-height: 100px;
	text-align: center;
	color: #fff;
}

之前一直不懂绝对定位的工作机制到底是怎样, 下面是查资料看到的:

  1. 在普通文档流中margin: auto相当于margin-top: 0; margin-bottom: 0;;
  2. position: absolute会脱离文档流, 脱离的部分将不会影响文档流中的内容.
  3. 给块区域内设置top: 0; right: 0;bottom: 0;left: 0, 浏览器将重新分配一个边界框, 这个时候的块区域会占满父级所有可用空间.
  4. 为这个块区域设置宽度或高度就可以防止该元素占满整个父级元素, 促使浏览器根据新的边界值重新计算margin: auto.
  5. 由于内容块被绝对定位, 脱离了正常的内容流, 浏览器会给margin-top,margin-bottom相同的值, 使元素块在先前定义的边界内居中.

2. 可视区域内水平垂直居中

把上面例子改为position: fixed; z-index: 999, 设置一个较大值的z-index; 如果不给这个块级元素设置宽高则会占满整个屏幕.

<div class="fixed-center">固定定位水平垂直居中</div>
.fixed-center{
	width: 200px;
	height: 200px;
	position: fixed;;
	z-index: 999;
	background: rgba(0, 0, 0, .3);
	top: 0; 
	left: 0;
	bottom: 0; 
	right: 0; 
	margin: auto;
	line-height: 200px;
	color: #fff;
	text-align: center;
}

3. 边栏垂直居中

有时需要将一个内容块固定在屏幕的左侧或者右侧, 可以向内容快加入像这样的 CSS 代码top: 20px; bottom: auto;; 由于已经声明了margin: auto, 内容块将会垂直居中在你定义的top/ right/ bottom/ left边界值内. 可以用left: 0; right: auto将内容快固定在左侧; right: 0; left: auto;将内容固定在右侧.

<div class="absolute-left">
	绝对定位在左侧
</div>
<div class="absolute-right">
	绝对定位在右侧
</div>
.absolute-left {
	position: absolute;
	left: 20px;
	right: auto;
	margin: auto;
	width: 150px;
	height: 80px;
	background: red;
	color: #fff;
	text-align: center;
	line-height: 80px;
}
.absolute-right {
	position: absolute;
	left: auto;
	right: 20px;
	margin: auto;
	width: 150px;
	height: 80px;
	background: green;
	color: #fff;
	text-align: center;
	line-height: 80px;
}

4. 自适应绝对定位居中

自适应绝对居中的优势就是对百分比的宽高完美支持, 甚至是max-width/ min-width或者是max-height/ max-width, 即使加上padding也不会影响绝对居中的实现.

<div class="wrapper-responsive">
	<div class="absolute-responsive">
		自适应绝对定位居中
	</div>
</div>
.wrapper-responsive{
	position: relative;
	top: 300px;
	width: 200px;
	height: 200px;
	border: thin solid black;
}
.absolute-responsive{
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	margin: auto;
	width: 60%;
	height: 60%;
	min-width: 50px;
	max-width: 150px;
	padding: 10px;
	text-align: center;
	color: #fff;
	background: skyblue;
}

5. 内容溢出

有时内容块的内容过多导致高度大于父级元素, 内容就会显示到块和容器的外面, 这种时候加个给内容块overflow: auto即可, 如果内容块没有padding的话加个max-height: 100%也行.

6. 可变高度

设置display: table, 内容块会垂直居上不过水平还是居中. 但是这个在一些浏览器上有问题( 如: IE/ FF); display: table-cell配合vertical-align: middle;也可实现垂直水平居中.

<div class="wrapper-table">
	<div class="table-center">
		table 水平居中
		内容内容内容内容内容内容内容内容内容内容内
	</div>
</div>
	
<div class="wrapper-table-cell">
	<div class="table-center-cell">
		table-cell 居中
		内容内容内容内容内容内容内容内容内容内容内
	</div>
</div>
/* tabel 居中 */
.wrapper-table{
	margin-top: 600px;
	display: table;
	height: auto;
	width: 200px;
	height: 200px;
	border: thin solid black;
}
.table-center{
	width: 80px;
	background: orange;
	color: #fff;
}

/* tabel-cell 居中 */
.wrapper-table-cell{
	margin-top: 600px;
	display: table-cell;
	height: auto;
	width: 200px;
	height: 200px;
	border: thin solid black;
	vertical-align: middle;
}
.table-center-cell{
	width: 100px;
	background: #FFD34E;
	color: #fff;
}

6. 负外边距

这个方法应该是很常用的方法了, 已知元素的宽高: 外边距margin的值取负数(没有box-sizing: border-box的情况下, 包括padding), 大小为 width/ height的一半, 再加上top: 50%; left: 50%, 这个不能自适应哦.

<div class="wrapper-margin">
	<div class="margin-center">
		margin 居中
	</div>
</div>
.wrapper-margin{
  position: relative;
	top: 100px;
	border: thin solid black;
	width: 200px;
	height: 200px;
}
.margin-center{
	width: 100px;
	height: 100px;
	background: #105B63;
	position: absolute;
	top: 50%;
	left: 50%;
	margin: -50px auto auto -50px;
	color: #fff;
	text-align: center;
	line-height: 100px;
}

7. 变形

这可以说是最简单的方法了, 不仅可以实现绝对居中的想过还可以实现可变宽高度. 内容块定义transform: translate(-50%, -50%)带上浏览器前缀, 再加上top: 50%; left: 50%即可.

<div class="wrapper-transform">
	<div class="transform-center">
		transform 居中
	</div>
</div>
.wrapper-transform{
	position: relative;
	top: 200px;
	border: thin solid black;
	width: 200px;
	height: 200px;
}
.transform-center{
	width: 100px;
	height: 100px;
	background: #BD4932;
	position: absolute;
	top: 50%;
	left: 50%;
	-webkit-transform: translate(-50%, -50%);
	-ms-transform: translate(-50%, -50%);
	-o-transform: translate(-50%, -50%);
	transform: translate(-50%, -50%);
	color: #fff;
	text-align: center;
}

8. Flexbox

CSS3的新属性也叫弹性盒子, 它不仅可以解决居中的问题还可以分栏或者其他的一些布局问题. 这里不多解释, 下次做一个详细的说明.

<div class="wrapper-flex">
	<div class="flex-center">
		弹性盒子居中
	</div>
</div>
.wrapper-flex{
	margin-top: 500px;
	width: 200px;
	height: 200px;
	border: thin solid black;
	display: flex;
	justify-content: center;
	align-items: center;
}
.flex-center{
	background: grey;
	color: #fff;
	text-align: center;
}

预览地址

2017-10-11 完

Methods

方法

JavaScript包含了一套小型的可用在标准类型上的标准方法集,
主要是针对数组/正则及字符串的一些处理.

Array

array.concat(item...)

concat 方法产生一个新的数组, 它包含的是一份 array 的浅复制
并把参数 item 追加在其后. 如果 item 是数组, 那么这个数组的
每个元素都会被添加.

let arr = [1, 2, 3];
let arr2 = [4, 5, 6];
let result = arr.concat(arr2, 'wow');

console.log(result); // [1, 2, 3, 4, 5, 6, 'wow'];

array.join(separator)

join 方法是把一个 array 以指定的分隔符构造成一个字符串.
它先把 array 中的每个元素构造成一个字符串, 然后以指定的
分隔符把它们都连接起来. 默认的 separate 是逗号, 可以用
空字符串作为 separate.

let array = ["a", "b", "c"];
array.push("d");

let result = array("|");
console.log(result); // "a|b|c|d"

array.pop()

pop 和 push 方法可以使 array 像堆栈一样工作. pop 方法移除数组
中的最后一个元素并返回该元素, 如果是空数组, 它将返回 undefined.

let arr = [1, 2, 3];
arr.pop()

console.log(arr); // 3

array.push(item...)

push 方法向数组的末尾添加一个或多个元素. 和 concat 方法不同的是,
他会修改 array, 如果 item 是一个数组, 会将整个参数数组作为一个元素
添加到 array 的末尾, 并返回这个新数组的长度.

let array = [1, 2, 3];
let arr = [4, 5, 6];

let result = array.push(arr. 'Hi');
console.log(result); 
// array: [1, 2, 3, [4, 5, 6], 'Hi']
// result: 5

array.reverse()

reverse 方法反转数组元素的顺序, 并返回数组本身.

let array = [1, 2, 3];

let result = array.reverse();
console.log(result); // [3, 2, 1]

array.shift()

shift 方法移除数组中的第一个元素并返回该元素. 如果是空数组
将会返回 undefined. shift 通常比 pop 慢得多.

let array = [1, 2, 3];
let result = array.shift();

console.log(result); // 1

array.slice(start, end)

slice 方法是截取 array 中的一段做浅复制. 复制 array[start] 开始
到复制 array[end]为止. end 参数是可选的, 默认值的长度是 array.length.
如果 start 的值大于等于 array.length, 会得到一个新的空数组.

let array = [1, 2, 3];

let a  = array.slice(0, 1); // [1]
let b = array.slice(1); // [2, 3]
let c = array.slice(-1); // [3]

array.sort(comparefn)

sort 方法是对数组中的元素排序,但他的默认比较函数是把被排序的元素都视为
字符串。 所以通常都是自己定义比较函数.

// 对字符串和数字排序
const compare = (a, b) => {
	if (a === b) {
		return 0
	}
	if (typeof a === typeof b) {
		return  a < b ? -1 : 1
	}
	return typeof a < typeof b ? -1 :1
}

let array = ['bb', 'aa', 2, 'cc', 3, 1, 7];

console.log(array.sort(compare())); // [ 1, 2, 3, 7, 'aa', 'bb', 'cc' ]

稳定性:排序后2个相等键值的顺序和排序之前它们的顺序相同.

  • 不稳定排序
const by = name => {
	// o/p 每组相比较的数据
	return (o, p) => {
		let a, b;

		if(o && p && typeof o === 'object' && typeof p === 'object') {
			a = o[name];
			b = p[name];
			// 全等时
			if (a === b) {
				return 0
			}
			// 同类型
			if (typeof a === typeof b) {
				return a < b ? -1 : 1 
			}
			// 不同类型
			return typeof a < typeof b ? -1 : 1
		}else {
			console.log('排序失败')
		}
	}
}

let s = [
	{first: 'Joe', last: 'DeRita'},
	{first: 'Moe', last: 'Howard'},
	{first: 'Joe', last: 'Besser'},
	{first: 'Shemp', last: 'Howard'},
	{first: 'Larry', last: 'Fine'},
	{first: 'Curly', last: 'Howard'},
]

console.log(s.sort(by('first')).sort('last'));
/*
[ 
	{ first: 'Curly', last: 'Howard' },
	{ first: 'Joe', last: 'DeRita' },
	{ first: 'Joe', last: 'Besser' },
	{ first: 'Larry', last: 'Fine' },
	{ first: 'Moe', last: 'Howard' },
	{ first: 'Shemp', last: 'Howard' }  
]
 */
  • 稳定排序
// 让函数接收两个参数, 当第一个函数相等时
// 由第二个参数再次比较, 第二个次要比较函数可选
const betterBy = (name, minor) => {
	return (o, p) => {
		let a, b;
		if (o && p && typeof o === 'object' && typeof 'object') {
			a = o[name];
			b = p[name];
			if (a === b) {
				// 用次要比较函数再次对比
				return typeof minor === 'function' ? minor(o, p) : 0
			}
			if (typeof a === typeof b) {
				return a < b ? -1 : 1
			}
			return typeof a < typeof b ? -1 : 1
		}else {
			console.log('排序失败');
		}
	}

}

let a = [
	{first: 'Joe', last: 'DeRita'},
	{first: 'Moe', last: 'Howard'},
	{first: 'Joe', last: 'Besser'},
	{first: 'Shemp', last: 'Howard'},
	{first: 'Larry', last: 'Fine'},
	{first: 'Curly', last: 'Howard'},
];

console.log(a.sort(by('last',by('first'))));
/*[ 
	{ first: 'Joe', last: 'Besser' },
	{ first: 'Joe', last: 'DeRita' },
	{ first: 'Larry', last: 'Fine' },
	{ first: 'Moe', last: 'Howard' },
	{ first: 'Shemp', last: 'Howard' },
	{ first: 'Curly', last: 'Howard' } 
]
 */

array.splice(start, deleteCount, item...)

splice 方法从 array 中移除一个或多个元素, 并用新的 item 替换他们.
start 是从 array 中移除元素的开始位置 ( 索引 ) , deleteCount 是要
删除元素的个数, item 参数如果有会被插入到被删除元素的位置上. 返回
被删除的元素.

let arr = ['b', 'a', 'c', 'bug'];
let remove = arr.splice(1, 1, 'newItem', 'Hi');

console.log(arr); // ['b', 'newItem', 'Hi','c', 'bug']
console.log(remove); // ['a']

array.unshift(item...)

unshift 方法向数组的开头插入一个或多个元素并返回数组新的长度.

let arr = ['a', 'b', 'c'];
let insert = arr.unshift('Hi', 'd');

console.log(arr); // ['Hi', 'd', 'a', 'b', 'c']
console.log(insert); // 5

RegExp

regexp.exec(string)

exec 方法是使用正则表达式的最强大(最慢)的方法. 如果它成功匹配
regexp 和字符串 string, 将返回一个数组. 数组中下标为0的元素包含
正则表达式 regexp 匹配的子字符串; 下标为1的元素是分组1捕获的文本;
下标为2的元素是分组2捕获的文本, 以此类推. 如果匹配失败则返回null.

regexp.test(string)

test 方法是使用正则表达式的最简单(最快)的方法. 如果该regexp 与 string
匹配, 它返回 true, 否则返回 false. 不要对这个方法使用 g 标识.

let b = /&.+/.test('frank &amp; beans');

console.log(b); // true

String

string.charAt(pos)

charAt 方法返回在 string 中 pos 位置处的字符串. 如果 pos 小于0或者
大于等于字符串的长度, 将返回空字符串.

let name = 'Cara';
let initial = name.charAt(0);

console.log(initial); // 'C'

string.concat(string...)

concat 方法把其他字符串连接起来返回一个新的字符串. 通常用+

string.indexOf(searchString, position)

indexOf 方法在 string 内查找另一个字符串 searchString. 如果被
找到返回第一个匹配字符串的位置, 否则返回-1. 可选参数 position
可设置从 string 的某个指定位置开始查找.

let text = 'Mississippi';
let p = text.indexOf('ss'); // 2
p = text.indexOf('ss', 3); // 5

string.lastIndexOf(searchString, position)

lastIndexOf 跟 indexOf 方法相反, 是从数组的末尾开始查找.
返回一个指定的字符串值最后出现的位置, 在一个字符串中的指定位置从后向前搜索.

let text = 'Mississippi';
let p = text.lastIndexOf('ss'); // 5
p = text.lastIndexOf('ss', 3); // 2
p = text.lastIndexOf('ss', 6); // 5

string.match(regexp)

match 方法让字符串和一个正则表达式进行匹配. 它依据g标识符来决定如何
进行匹配. 如果没有g标识符, 那么调用 string.match(regexp)的结果与
调用regexp.exec(string)的结果相同. 如果有g标识符, 那么它返回一个
包含所有匹配项(除捕获分组)的数组.

string.replace(searchValue, replaceValue)

replace 方法对 string 进行查找和替换操作, 并返回一个新的字符串. 参数
searchValue 可以是一个字符串或者一个正则表达式对象. 如果是一个字符串,
那么 searchValue 只会把第一次匹配的出现的地方替换掉; 如果是正则表达式
带有g标识符, 则会替换点所有匹配项.

let str = '1-10-1001';
let reg = /-(\d+)-/;

str.replace(reg, '栋$1单元');
console.log(str); // 1栋10单元1001

string.search(regexp)

search 方法和 indexOf 方法类似, 只是它只接受一个正则表达式对象作为参数
而不是一个字符串. 如果找到匹配, 它返回第一个匹配的首字符位置. 如果没有
返回-1. 此方法会忽略g标识符.

string.slice(start, end)

slice 方法复制 string 的一部分构造成一个新的字符串. 如果 start 参数是负数
, 他将与 string.length 相加. end 参数是可选的, 默认是 string.length. 如果
end 参数是负数, 也会与 string.length 相加. end 参数等于你想取的最后一个字符
的位置加1.

// str.length == 39
let str = 'and in it he says "Any damn fool could';
let a = str.slice(0, 3); // 'and'
let b = str.slice(-5); // 'could'

string.split(separator, limit)

split 方法把 string 以指定的分隔符构造成一个字符串数组. 可选参数
limit 可以限制被分割片段的数量. separator 可以是一个字符串或者一个
正则表达式. 此方法会忽略g标识符.

let str = '0123456789';
let a = str.split('', 5);

console.log(a); // ['0', '1', '2', '3', '4']

string.substring(start, end)

substring 方法和slice 方法一样, 只是不能处理负数. 所以用slice代替它

string.toLocaleLowerCase()

toLocaleLowerCase 方法返回一个新的字符串, 它使用本地化的规则把这个 string
中的所有字母转换为小写格式.

string.toLocaleUpperCase()

toLocaleUpperCase 方法返回一个新的字符串, 它使用本地化的规则把这个 string
中的所有字母转换为大写格式.

17/9/21

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.