当你对一个文档进行布局时,浏览器引擎会根据css-box模型将全部元素描述为一个盒子,css会决定这些盒子的大小,位置,属性(颜色边框等)css
盒模型分为两类:IE盒模型和标准盒模型,二者区别在于html
IE盒模型的width/height = content +border + padding
标准盒模型的width/height = content
复制代码
IE盒模型jquery
当你想让两个子容器float:left,宽度各50%,而后给一点padding,最后让子容器并排充满父容器,一切想的挺美好,然而你发现结果并非这么美好,由于子容器的盒子宽度已经超出了父容器的一半,致使了折行,因而,width就不能50%了,只能是50%再减去padding的像素值程序员
// W3C 标准盒模型(浏览器默认)
box-sizing: content-box;
// IE 怪异盒模型
box-sizing: border-box;
//避免css在不一样浏览器下的表现不一样,最好加上
*, *:before, *:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
复制代码
当子元素设置position或是float时,子元素会乱跑,给父元素设置BFC,子元素便可以依旧被父元素包裹 2. 和浮动元素产生边界。web
通常状况下若是没有 BFC的话,咱们想要让普通元素与浮动元素产生左右边距,须要将 maring 设置为浮动元素的宽度加上你想要产生边距的宽度。编程
这里的浮动元素的宽度为 200px ,若是想和它产生 20px 的右边距,须要将非浮动元素的 margin-left 设置为 200px+20px 。windows
<div class="box" id="box">
<p>Lorem ipsum dolor sit.</p>
<div style="overflow: hidden;">
<p>Lorem ipsum dolor sit.</p>
</div>
<p>Lorem ipsum dolor sit.</p>
</div>
复制代码
.one {
float: left;
width: 100px;
height: 100px;
background-color: pink;
}
.two {
height: 200px;
background-color: red;
/* 设置 BFC */
overflow: hidden;
}
<div class="one"></div>
<div class="two"></div>
复制代码
侵占 数组
圣杯布局和双飞翼布局解决的问题是同样的,就是两边定宽,中间自适应的三栏布局(中间栏放在文档流前面优先渲染!)浏览器
圣杯布局和双飞翼布局解决问题的方案在前一半是相同的: 也就是三栏所有浮动,但左右两栏加上负margin让其跟中间栏div并排。bash
不一样在于解决 “中间栏div内容不被遮挡” 问题的思路不同。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
</head>
<style>
body {
min-width: 550px; /* 2x leftContent width + rightContent width */
font-weight: bold;
font-size: 20px;
}
#header, #footer {
background: rgba(29, 27, 27, 0.726);
text-align: center;
height: 60px;
line-height: 60px;
}
#footer {
clear: both;
}
#container {
padding-left: 200px; /* leftContent width */
padding-right: 150px; /* rightContent width */
overflow: hidden;
}
#container .column {
position: relative;
float: left;
text-align: center;
height: 300px;
line-height: 300px;
}
#center {
width: 100%;
background: rgb(206, 201, 201);
}
#left {
width: 200px; /* leftContent width */
right: 200px; /* leftContent width */
margin-left: -100%;
background: rgba(95, 179, 235, 0.972);
}
#right {
width: 150px; /* rightContent width */
margin-right: -150px; /* rightContent width */
background: rgb(231, 105, 2);
}
</style>
<body>
<div id="header">#header</div>
<div id="container">
<div id="center" class="column">#center</div>
<div id="left" class="column">#left</div>
<div id="right" class="column">#right</div>
</div>
<div id="footer">#footer</div>
</body>
</html>
复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
</head>
<style>
body {
min-width: 550px;
font-weight: bold;
font-size: 20px;
}
#header, #footer {
background: rgba(29, 27, 27, 0.726);
text-align: center;
height: 60px;
line-height: 60px;
}
#container {
display: flex;
}
#container .column {
text-align: center;
height: 300px;
line-height: 300px;
}
#center {
flex: 1;
background: rgb(206, 201, 201);
}
#left {
width: 200px;
background: rgba(95, 179, 235, 0.972);
}
#right {
width: 150px;
background: rgb(231, 105, 2);
}
</style>
<body>
<div id="header">#header</div>
<div id="container">
<div id="left" class="column">#left</div>
<div id="center" class="column">#center</div>
<div id="right" class="column">#right</div>
</div>
<div id="footer">#footer</div>
</body>
</html>
复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>实现三栏水平布局之双飞翼布局</title>
<style type="text/css">
.left, .main, .right {
float: left;
min-height: 130px;
text-align: center;
}
.left {
margin-left: -100%;
background: green;
width: 200px;
}
.right {
margin-left: -300px;
background-color: red;
width: 300px;
}
.main {
background-color: blue;
width: 100%;
}
.content{
/* 关键点:用margin把div挤到中间正常展现*/
margin: 0 300px 0 200px;
}
</style>
</head>
<body>
<div class="container">
  <div class="main">
   <div class="content">main</div>
</div>
  <div class="left">left</div>
  <div class="right">right</div>
</div>
</body>
</html>
复制代码
JS中一切皆对象,而每一个对象都有一个原型(Object除外),这个原型,大概就像Java中的父类,因此,基本上你能够认为原型就是这个对象的父对象,即每个对象(Object除外)内部都保存了它本身的父对象,这个父对象就是原型。通常建立的对象若是没有特别指定原型,那么它的原型就是Object(这就很相似Java中全部的类默认继承自Object类)。
在js中,对象建立方法常见的以下
//第一种,手动建立
var a={'name':'lala'};
//第二种,构造函数
function A(){
this.name='lala';
}
var a=new A();
//第三种,class (ES6标准写法)
class A{
constructor(){
//super();此处没有使用extends显式继承,不可以使用super()
this.name='lala';
}
}
var a=new A()
//其实后面两种方法本质上是一种写法
复制代码
这三种写法建立的对象的原型(父对象)都是Object,须要提到的是,ES6经过引入class ,extends等关键字,以一种语法糖的形式把构造函数包装成类的概念,更便于你们理解。是但愿开发者再也不花精力去关注原型以及原型链,也充分说明原型的设计意图和类是同样的。
当对象被建立以后,查看它们的原型的方法不止一种,之前通常使用对象的proto属性,ES6推出后,推荐用Object.getPrototypeOf()方法来获取对象的原型
function A(){
this.name='lala';
}
var a=new A();
console.log(a.__proto__)
//输出:Object {}
//推荐使用这种方式获取对象的原型
console.log(Object.getPrototypeOf(a))
//输出:Object {}
复制代码
不管对象是如何建立的,默认原型都是Object,在这里须要说起的比较特殊的一点就是,经过构造函数来建立对象,函数A自己也是一个对象,而A有两个指向表示原型的属性,分别是proto和prototype,并且两个属性并不相同
function A(){
this.name='lala';
}
var a=new A();
console.log(A.prototype)
//输出:Object {}
console.log(A.__proto__)
//输出:function () {}
console.log(Object.getPrototypeOf(A))
//输出:function () {}
复制代码
函数的的prototype属性只有在看成构造函数建立的时候,把自身的prototype属性值赋给对象的原型。而实际上,做为函数自己,它的原型应该是function对象,而后function对象的原型才是Object。
其实原型和类的继承的用法是一致的:当你想用某个对象的属性时,将当前对象的原型指向该对象,你就拥有了该对象的使用权了。
function A(){
this.name='world ';
}
function B(){
this.bb="hello"
}
var a=new A();
var b=new B();
Object.setPrototypeOf(a,b);
//将b设置为a的原型,此处有一个问题,即a的constructor也指向了B构造函数,可能须要纠正
a.constructor=A;
console.log(a.bb)
//输出 hello
复制代码
若是使用ES6来作的话则简单许多,甚至不涉及到prototype这个属性
class B{
constructor(){
this.bb='hello'
}
}
class A extends B{
constructor(){
super()
this.name='world'
}
}
var a=new A();
console.log(a.bb+" "+a.name);
//输出hello world
console.log(typeof(A))
//输出 "function"
复制代码
怎么样?是否是已经彻底看不到原型的影子了?活脱脱就是类继承,可是你也看获得实际上类A 的类型是function,因此说,本质上class在JS中是一种语法糖,JS继承的本质依然是原型,不过,ES6引入class,extends 来掩盖原型的概念也是一个很友好的举动,对于长期学习那些类继承为基础的面对对象编程语言的程序员而言。
这个概念其实也变得比较简单,能够类比类的继承链条,即每一个对象的原型往上追溯,一直到Object为止,这组成了一个链条,将其中的对象串联起来,当查找当前对象的属性时,若是没找到,就会沿着这个链条去查找,一直到Object,若是还没发现,就会报undefined。那么也就意味着你的原型链不能太长,不然会出现效率问题
做用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,做用域决定了代码区块中变量和其余资源的可见性。简单来讲做用域就是用来隔离变量,不一样做用域下的同名变量不会有冲突。
任何地方都能访问到的对象拥有全局做用域
var a = 2;
function fn() {
var b =1;
return b;
}
console.log(fn())//1
console.log(a);//2
console.log(b);//b is not defined
复制代码
var a = 2;
function fn() {
b =1;
return b;
}
console.log(fn())//1
console.log(a);//2
console.log(b);//1
复制代码
局部做用域通常只在固定的代码片断内可访问到,最多见的例如函数内部,因此在一些地方会把这种做用域成为函数做用域。
上文代码一中,b是函数内部声明并赋值,拥有局部做用域,只能带函数fn内部使用,在fn外部使用就会报错,这就是局部做用域的特性,外部没法访问。
ES5只有全局做用域和函数做用域,没有块级做用域,会带来下面问题:
ES6引入了块级做用域,明确容许在块级做用域中声明函数,let和const命令都涉及块级做用域。
块级做用域容许声明函数只在使用大括号的状况下成立,若是未使用大括号,会报错。
if (true) {
function func1() {} // 不报错
}
if (true)
function func2() {} // 报错
复制代码
通俗地讲,当声明一个函数时,局部做用域一级一级向上包起来,就是做用域链。
1.当执行函数时,老是先从函数内部找寻局部变量
2.若是内部找不到(函数的局部做用域没有),则会向建立函数的做用域(声明函数的做用域)寻找,依次向上
var a =1;
function fn() {
var a = 10;
function fn1() {
var a =20;
console.log(a);//20
}
function fn2 () {
console.log(a);//10
}
fn1();
fn2();
}
fn();
console.log(a)//1
复制代码
当执行fn1时,建立函数fn1的执行环境,并将该对象置于链表开头,而后将函数fn的调用对象放在第二位,最后是全局对象,做用域链的链表的结构是fn1->fn->window。从链表的开头寻找变量a,即fn1函数内部找变量a,找到了,结果是20。
一样,执行fn2时,做用域链的链表的结构是fn2->fn->window。从链表的开头寻找变量a,即fn2函数内部找变量a,找不到,因而从fn内部找变量a,找到了,结果是10。
最后在最外层打印出变量a,直接从变量a的做用域即全局做用域内寻找,结果为1。
提到做用域就不得不提到闭包,简单来说,闭包外部函数可以读取内部函数的变量。
优势:闭包能够造成独立的空间,永久的保存局部变量。
缺点:保存中间值的状态缺点是容易形成内存泄漏,由于闭包中的局部变量永远不会被回收
function fn1() {
var n = 999;
nAdd = function () {
n += 1
}
function fn2() {
console.log(n)
}
return fn2
}
var result = fn1();
result();//999
nAdd();//执行n +=1;
result();//1000
复制代码
在 ES5 中,其实 this 的指向,始终坚持一个原理:this 永远指向最后调用它的那个对象
var name = "windowsName";
function a() {
var name = "Cherry";
console.log(this.name); // windowsName
console.log("inner:" + this); // inner: Window
}
a();
console.log("outer:" + this) // outer: Window
复制代码
调用a的时候,前面没有调用对象那么即为全局对象window。这里咱们没有使用严格模式,若是使用严格模式的话,全局对象就是 undefined,那么就会报错 Uncaught TypeError: Cannot read property 'name' of undefined。
var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this.name); // windowsName
}
}
var f = a.fn;
f();
复制代码
这里你可能会有疑问,为何不是 Cherry,这是由于虽然将 a 对象的 fn 方法赋值给变量 f 了,可是没有调用,再接着跟我念这一句话:“this 永远指向最后调用它的那个对象”,因为刚刚的 f 并无调用,因此 fn() 最后仍然是被 window 调用的。因此 this 指向的也就是 window。 出处。
目前主要有如下几种方法
箭头函数的 this 始终指向函数定义时的 this,而非执行时。箭头函数中没有 this 绑定,必须经过查找做用域链来决定其值,若是箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,不然,this 为 undefined”。
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( () => {
this.func1()
},100);
}
};
a.func2() // Cherry
复制代码
若是不使用 ES6,那么这种方式应该是最简单的不会出错的方式了,咱们是先将调用这个函数的对象保存在变量 this_ 中,而后在函数中都使用这个 this_,这样 this_ 就不会改变了
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
var this_ = this;
setTimeout( function() {
this_.func1()
},100);
}
};
a.func2() // Cherry
复制代码
//apply
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.apply(a),100);
}
};
a.func2() // Cherry
//call
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.call(a),100);
}
};
a.func2() // Cherry
//bind
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.bind(a)(),100);
}
};
a.func2() // Cherry
复制代码
apply定义
apply() 方法调用一个函数, 其具备一个指定的this值,以及做为一个数组(或相似数组的对象)提供的参数
复制代码
语法
fun.apply(thisArg, [argsArray])
复制代码
二者基本相似,区别在于传入的参数不一样 call语法
fun.call(thisArg[, arg1[, arg2[, ...]]])
复制代码
apply 和 call 的区别是 call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.apply(a,[1,2]) // 3
复制代码
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.call(a,1,2) // 3
复制代码
bind()方法建立一个新的函数,当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供以前提供一个给定的参数序列。
因此bind是建立一个新的函数,必须手动调用
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.bind(a,1,2)() // 3
复制代码
Function.prototype._call = function (context = window) {
var context = context;
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args +')');
delete context.fn
return result;
}
// 测试一下
var value = 2;
var obj = {
value: 1
}
function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
bar._call(null); // 2
console.log(bar._call(obj, 'kevin', 18));
// 1
// Object {
// value: 1,
// name: 'kevin',
// age: 18
// }
复制代码
Function.prototype.apply = function (context = window, arr) {
var context = context;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
}
else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')')
}
delete context.fn
return result;
}
复制代码
Function.prototype._bind = function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {};
var fBound = function () {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
}
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}
复制代码
// 经过字面量方式实现的函数each
var each = function(object, callback){
var type = (function(){
switch (object.constructor){
case Object:
return 'Object';
break;
case Array:
return 'Array';
break;
case NodeList:
return 'NodeList';
break;
default:
return 'null';
break;
}
})();
// 为数组或类数组时, 返回: index, value
if(type === 'Array' || type === 'NodeList'){
// 因为存在类数组NodeList, 因此不能直接调用every方法
[].every.call(object, function(v, i){
return callback.call(v, i, v) === false ? false : true;
});
}
// 为对象格式时,返回:key, value
else if(type === 'Object'){
for(var i in object){
if(callback.call(object[i], i, object[i]) === false){
break;
}
}
}
}
复制代码
参考文献
做者:拉丁吴 连接:juejin.im/post/57f336… 来源:掘金
做者:sunshine小小倩 连接:juejin.im/post/59bfe8… 来源:掘金
做者:Chris_Ping 连接:juejin.im/post/5d1f1c… 来源:掘金