valar morghulis


  • 首页

  • 标签

  • 分类

  • 归档

JavaScript 作用域和作用域链学习

发表于 2018-03-25 | 分类于 JavaScript |

作用域
一个变量的作用域是程序源代码中定义这个变量的区域。
而在ES5中只分为全局作用域和函数作用域,也就是说for,if,while等语句是不会创建作用域的。ES6(let,const)除外。

1
2
3
4
5
6
 //全局作用域
var a = 123;
function aa () {
//局部作用域
var b = 456;
}

声明提前
JavaScript函数里声明的所有变量(但不涉及赋值)都被“提升”至函数体的顶部,在代码开始运行之前。这个特性被称为声明提前。

var a = "g";
function f() {
  console.log(a); //输出undefined
  var a = "l";
  console.log(a); //输出"l"
} 

由于函数作用域的特性,局部变量在整个函数体始终是有定义的,也就是说,函数体的局部变量覆盖了同名全局变量。在函数体内,变量a被“提前”了,提前至函数体的顶部,所以第一次输出的是undefined,那时候还没赋值,但代码执行到var语句时候,局部变量才会被赋值。因此第二次输出则是“l”。此代码过程如下:

1
2
3
4
5
6
7
 var a = "g";
function f() {
var a;
console.log(a); //输出undefined
a = "l";
console.log(a); //输出"l"
}

因此一些程序员特意将变量声明放在函数体的顶部,而不是将声明靠近放在使用变量之处。

作用域链
先看一段简单代码,代码如下:

1
2
3
4
5
6
7
var name = "wythe";
function one () {
console.log(name); //wythe
var firend = "zero";
}
one();
console.log(firend); //报错

看到代码可知,name是在全局作用域中声明的全局变量,而firend则是在函数作用域中声明的局部变量。在执行时候你会发现函数作用域能够访问到在全局作用域中name这个变量,而全局作用域却不能访问到函数作用域的friend的变量,原因是作用域链!
作用域链的规则:
外部不能访问内部变量,内部可以访问外部变量
为什么会有这样规则?因为是执行环境所规定的。

执行环境定义了变量或函数有权访问其他数据,决定了它们的行为。每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。
全局执行环境是最外围的一个执行环境。在Web浏览器中,全局执行环境被认为是window对象。某个执行环境中所有所有代码执行完毕后,该环境被销毁,保存在其中的所有的变量和函数定义也随之销毁。

补充说明:需要了解一些概念,变量对象(Variable Object)、活动对象(Activation Object)、函数的属性[[scope]].

变量对象指的是变量对象(缩写为VO)是一个与执行上下文相关的特殊对象,它存储着在上下文中声明的内容有:变量 (var, 变量声明)、函数声明和函数的形参。

执行上下文(执行环境):每次当控制器转到ECMAScript可执行代码的时候,即会进入到一个执行上下文。执行上下文(简称-EC)是ECMA-262标准里的一个抽象概念,用于同可执行代码(executable code)概念进行区分。
活动对象指的是由函数的运行期上下文(代码执行前)创建,在运行时可变,初始时只有 arguments 属性,通过变量的初始化,包含了局部变量、命名参数、 this 等。

JS中关于if(xx)和 a==b

发表于 2018-03-22 | 分类于 JavaScript |

if判断

在js中一般不使用if(变量)的方式使用if条件语句,容易产生你所不希望的结果,
先来看看如下的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if ("hello") {
console.log("hello")
}//1
if ("") {
console.log('empty')
}//2
if (" ") {
console.log('blank')
}//3
看了上面三个if语句,你能准确得出结果吗?
来看第一个,if('hello')和if(" ")和if从直观上应该是输出结果,if("")应该是不输出结果的,经过测试的却如此。那么再看下面的代码

if ([0]) {
console.log('array')
}

if('0.00'){
console.log('0.00')
}

这里就比较模糊了,按理说还是输出结果的,但是没有特别确定,经过测试都输除了结果。

那么上面的if是按照什么原理的呢?
js是把括号里面的变量转化成布尔类型的变量然后进行判断的。

类型 结果
Undefined false
Null false
Boolean 直接判断
String 除了空字符串为false,其他为true
Number 除了0,-0,+0,Nan其他为 true
Object true
记住这些以后看到if(变量)就可以轻松的得到结果了,当然最好还是避免使用判断语句中直接使用变量的情况。

相等运算符 ==

下面来看看不严格相等符号
==在比较相同类型的数据时,和===是一样的结果。不同的数据类型===会直接返回false,而==则不一样,有如下的规则

原始类型的值
原始类型的数据会转换成数值类型再进行比较。
对象与原始类型值比较
对象(这里指广义的对象,包括数组和函数)与原始类型的值比较时,对象转化成原始类型的值,再进行比较。
undefined 和 null
undefined和null与其他类型的值比较时,结果都为false,它们互相比较时结果为true。
相等运算符的缺点:
相等运算符隐藏的类型转换,会带来一些违反直觉的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
0 == ''             // true
0 == '0' // true

2 == true // false
2 == false // false

false == 'false' // false
false == '0' // true

false == undefined // false
false == null // false
null == undefined // true

' \t\r\n ' == 0 // true

所以日常最好使用严格相等运算符===

JS面向对象与原型链继承

发表于 2017-12-24 | 分类于 JavaScript |

由于最开始是先接触Python的中面向对象,继承的语法以及思路开始的。之后当接触到了JavaScript的的面向对象语法时是觉得有些别捏的。JS本身是不提供class的实现的,而是基于原型链。

面向对象

1
2
3
4
5
6
7
8
9
10
function People(name){
this.name = name
}

People.prototype.sayName = function(){
console.log()
}

var p = new People("yangchenhao")
p.sayName()

当new一个函数时发生了三件事情

  1. 创建了一个空对象,把空对象的proto属性指向People.prototype
  2. 执行People函数,函数中的this代表这个刚创建的新对象
  3. 返回这个对象

对于第三步,如果构造函数中有return,分情况讨论。如果return的是基本类型,会忽略不计。如果return的是引用类型,则返回这个引用类型

原型图

Tips

任何函数都有.prototype这个属性,对应的值叫做原型对象,这个原型对象可以由被这个函数new的所有对象共享

继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function Dialog(target){
this.target = target
}

Dialog.prototype.show = function(){
console.log(this.target + ' show')
}

Dialog.prototype.hide = function(){
console.log(this.target + ' hide')
}

var dialog = new Dialog('body')

dialog.show()

function Message(target, name){
Dialog.call(this, target) // Message构造函数中执行一遍Dialog函数构造过程
this.name = name
}

Message.prototype = Object.create(Dialog.prototype) // 将Message.prototype中_proto_属性指向Dialog.prototype 相当于继承Dialog中的方法
Message.prototype.success = function(){
console.log(this.name, ' success')
}

var msgBox = new Message('main', 'msg')
msgBox.show()
msgBox.success()

Dialog.call(this, target)的作用是: 执行函数 Dialog(target),执行的过程中里面遇到 this 换成当前传递的 this

Object.create(Dialog.prototype)的作用是:创建一个空对象,空对象的proto等于 Dialog.prototype

前端性能优化

发表于 2017-12-21 | 分类于 JavaScript |

梳理整理一下前端性能优化常见思路与技巧

性能优化的目的是让用户觉得你的网站访问起来速度快,即使实际速度可能并没有变,只是感觉变快了。因此优化可以从两个方向,即真的快和感觉变快了。

真的快

真的快就是让网站资源以最快速度到达用户浏览器,可以按照下面的思路和方法去优化。

传输的内容体积要小

  1. 图片要压缩
  2. 图片根据支持格式选择体积更小的格式
  3. css,js内容压缩
  4. 服务端开启Gzip,在传输数据之前再次压缩

传输的内容数量要少

  1. 图片图标合并(css sprite),svg图标合并(svg sprite)
  2. css,js文件打包合并

网速要足够快

  1. 服务器出口带宽够
  2. 南北差异,不同地方部署不同服务器
  3. 静态资源放CDN

服务器响应要及时

  1. 接口响应速度要快(数据库优化,查询优化,算法优化)
  2. cpu,内存,硬盘读写不要成为瓶颈,多加机器
  3. 重要页面静态化。服务端提前渲染生成静态页面,用户访问时直接返回

能重复利用的资源要利用好

  1. 服务器设置合适的静态资源缓存时间
  2. 前端文件打包时做合理的分块,让公共资源缓存后能被多个页面复用

暂时不需要的资源先不要

  1. 图片懒加载
  2. 功能,模块,组件按需加载

将来需要的资源抽空先拿到

  1. DNS 预解析
  2. 预连接
  3. 预获取
  4. 预渲染

体验快

体验快就是网站交互是流畅的,舒适的。

滚动页面不要有迟滞感

  1. 短时间连续大量触发操作要节流

常见操作不要拖泥带水

  1. DOM操作不能过于频繁
  2. 不要出现内存泄漏
  3. 优化复杂算法

动画不要卡顿

  1. 多用CSS动画,少用JS动画
  2. 开启硬件加速
  3. 动画或过渡执行时间不要太久

臆想的优化不是优化,无明显成效的优化不是优化。浏览器的性能已经足够快,不要因为“过渡优化”牺牲代码的可读性

先做简单见效快的优化,再做复杂见效慢的优化。

ES6常用语法汇总

发表于 2017-12-06 | 分类于 JavaScript |

ECMAScript 6(简称ES6)是JavaScript语言的下一代标准。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。

虽然现在不是所有浏览器都能兼容ES6全部特性,但是越来越多的程序员在实际项目当中已经开始使用ES6。同时配合Babel等工具,ES6的普及也是越来越广泛。下面总结一下开发当中使用频率比较高的ES6新语法。

let, const

这两个的用途和var类似,都是用来声明变量,下面例子

1
2
3
4
5
6
7
8
9
var name = 'zach'

while (true) {
var name = 'obama'
console.log(name) // obama
break
}

console.log(name) // obama

使用var两次输出都是obama,因为ES5只有全局作用域和函数作用域,没有块级作用域。而let实际上为JavaScript新增了块级作用域。用它所声明的变量,只在let命令所在的代码块内有效。

1
2
3
4
5
6
7
8
9
let name = 'zach'

while (true) {
let name = 'obama'
console.log(name) // obama
break
}

console.log(name) // zach

另一个var带来的不合理场景就是用来计数循环变量泄露为全局变量

1
2
3
4
5
6
7
var a = []
for (var i = 0; i < 10; i++) {
a[i] = function() {
console.log(i)
}
}
a[6]() // 10

代码当中变量i是var声明的,在全局范围内都有效。所以每一次循环,新的i值都会覆盖旧值,导致输出的是最后一轮的i的值。而使用let则不会出现这个问题。

1
2
3
4
5
6
7
8
var a = []

for (let i = 0; i < 10; i++) {
a[i] = function() {
console.log(i)
}
}
a[6]()

const也用来声明变量,但是声明的是常量。一旦声明,常量的值就不能改变

1
2
3
const PI = Math.PI

PI = 33 // Module build failed: SyntaxError: /es6/app.js: "PI" is read-only

当我们尝试改变const声明的常量时,浏览器就会报错。
const有一个很好的应用场景,就是当我们引入第三方库时声明的变量,用const来声明可以避免未来不小心重命名而导致出现bug

1
const monent = require('moment')

class,extends,super

当初最早是先接触了python的面向对象的语法,后来接触到js的原型链,继承时觉得特别繁杂奇怪,直到再后来看到ES6中新添加的语法特性,顿时就觉得清晰了不少。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Animal {
constructor(){
this.type = 'animal'
}
say(say){
console.log(this.type + ' says ' + say)
}
}

let animal = new Animal()
animal.says('hello')

class Cat extends Animal {
constructor(){
super()
this.type = 'cat'
}
}

let cat = new Cat()
cat.says('hello') //cat says hello

super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。

ES6的继承机制,实质就是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

arrow function

1
2
function(i){ return i + 1; } //ES5
(i) => i + 1 //ES6

如果函数体内较复杂,则需用{}把代码包起来

1
2
3
4
5
6
7
function(x, y) {
x++;
y--;
return x + y;
}

(x, y) => {x++; y--; return x + y}

除了语法简洁之外,箭头函数还有一个非常好的优点,当我们使用箭头函数时,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象,它的this是继承外面的,因此内部this就是外层代码块的this。

代码例子如下

1
2
3
4
5
6
7
8
9
10
11
12
13
class Animal {
constructor(){
this.type = 'animal'
}
says(say){
setTimeout(function(){
console.log(this.type + ' says' + say)
}, 1000)
}
}

var animal = new Animal()
animal.says('hi') //undefined says hi

运行上面的代码会报错,因为setTimeout 中的this是指向全局对象。传统解决方法有两种

第一种是将this传给self,再用self来指代this

1
2
3
4
5
6
says(say){
var self = this;
setTimeout(function(){
console.log(self.type + ' says' + say)
}, 1000)
}

第二种方法是用bind(this)

1
2
3
4
5
says(say){
setTimeout(function(){
console.log(this.type + ' says' + say)
}.bind(this), 1000)
}

现在有了箭头函数,就不需要这么麻烦

1
2
3
4
5
6
7
8
9
10
11
12
13
class Animal {
constructor(){
this.type = 'animal'
}
says(say){
setTimeout( () => {
console.log(this.type + ' says' + say)
}, 1000)
}
}

var animal = new Animal()
animal.say('hi') //animal says hi

template string

当要插入大段的html内容到文档当中去时,传统写法非常麻烦

1
2
3
4
5
6
$("#result").append(
"There are <b>" + basket.count + "</b>" +
"items in your basket, " +
"<em>" + basket.onSale +
"</em> are on sale!"
)

如果用ES6的新特性模板字符串可以直接这么写

1
2
3
4
5
$("#result").append(`
There are <b>${basket.count}<b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`)

destructuring

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,叫解构赋值

1
2
3
4
let cat = 'ken'
let dog = 'lili'
let zoo = {cat: cat, dog: dog}
console.log(zoo) // object {cat: "ken", dog: "lili"}

用ES6完全可以这么写

1
2
3
4
let cat = "ken"
let dog = "lili"
let zoo = {cat, dog}
console.log(zoo) // object {cat: "ken", dog: "lili"}

反过来能这样赋值

1
2
3
let dog = {type: 'animal', many: 2}
let {type, many} = dog
console.log(type, many) // animal 2

default, rest

default 是指可以给函数参数添加默认值

传统方法是这样

1
2
3
4
5
function animal(type){
type = type || 'cat'
console.log(type)
}
animal()

如果用ES6可以直接这样写

1
2
3
4
function animal(type="cat"){
// console.log(type)
}
animal()

rest语法也挺简单

1
2
3
4
function animals(...types){
console.log(types)
}
animals('cat', 'dog', 'fish') //["cat", "dog", "fish"]

import export

传统组织js文件的方式缺乏模块化体系,无法将一个庞大js工程拆分成一个个功能相对独立但相互依赖的小工程,再用简单方法把它们连接起来。这可能导致两个问题。

  1. js代码变得臃肿难以维护
  2. 我们需要注意每个script标签在html的位置,因为它们通常有依赖关系

在ES6之前,我们需要利用第三方方案如CommonJS(服务器端)和AMD(浏览器端,如require.js)

传统的写法

首先是require.js的写法。假设有两个js文件: index.js 和 content.js 现在需要在 index.js 中使用 content.js 返回的结果

1
2
3
4
// content.js
define('content.js', function(){
return 'A cat';
})

然后require

1
2
3
4
// index.js
require(['./content.js'], function(animal){
console.log(animal);
})

CommonJS

1
2
3
4
5
//index.js
var animal = require('./content.js')

//content.js
module.exports = 'A cat'

ES6的写法

1
2
3
4
5
//index.js
import animal from './content'

//content.js
export default 'A cat'

浏览器跨域问题的几种解决方案

发表于 2017-12-05 | 分类于 HTML与CSS |

跨域问题出现的原因是由于浏览器的同源限制。

同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。

一个源的定义: 如果协议,端口(如果指定了一个)和域名对于两个页面是相同的,则两个页面具有相同的源。

通常解决跨域问题的方法包括以下几种

  1. jsonp
  2. cors
  3. 降域
  4. postmessage

jsonp

原理

  • 首先是利用动态添加script标签,定制src属性来实现跨域
  • 通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数后再返回,实现服务器端向客户端通信
  • 由于使用script标签的src属性,因此只支持get方法

jsonp简单实现

一个简单的jsonp实现,其实就是拼接url,然后动态的添加一个script元素到头部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function jsonp(req) {
var script = document.createElement('script')
var url = req.url + '?callback=' + req.callback.name
script.src = url
document.getElementsByTagName('head')[0].appendChild(script)
}

// 调用代码
function hello(res) {
console.log('hello ' + res.data)
}

jsonp({
url: "",
callback: hello
})

//服务器端代码
var http = require('http')
var urllib = require('url')

var port = 8080
var data = {'data': 'world'}

http.createServer(function(req,res){
var params = urllib.parse(req.url, true)
if(params.query.callback){
console.log(params.query.callback)
//jsonp
var str = params.query.callback + '(' + JSON.stringify(data) + ')'
res.end(str)
} else {
res.end()
}
}).listen(port, function(){
console.log('jsonp server is on')
})

上面的实现比较简单,有一些不足的地方

  1. 我们传递的回调必须是一个全局方法,要尽量减少全局方法使用
  2. 需要加入一些参数校验,确保接口正常执行

cors

CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

  1. 浏览器先根据同源策略对前端页面和后台交互地址做匹配,若同源,则直接发送数据请求;若不同源,则发送跨域请求。
  2. 服务器解析程序收到浏览器跨域请求后,根据自身配置返回对应文件头。若未配置过任何允许跨域,则文件头里不包含Access-Control-Allow-origin 字段,若配置过域名,则返回Access-Control-Allow-origin + 对应配置规则里的域名的方式。
  3. 浏览器根据接收到的http文件头里的Access-Control-Allow-origin字段做匹配,若无该字段,说明不允许跨域;若有该字段,则对字段内容和当前域名做对比,如果同源,则说明可以跨域,浏览器发送请求;若不同源,则说明该域名不可跨域,不发送请求

降域

  1. 把child.a.com和a.com和xxx.child.a.com都可以降域为a.com。因此只能在不同子域名之间实现
  2. 实现的话需要在两个需要进行跨域的网站script都写document.domain = ‘a.com’进行降域
  3. 其中ajax不受降域的影响,得用iframe在页面中引用另一个页面的这种方式
  4. 降域有安全性的问题,如果一个子域名被攻击,多个被降域的域名都会被连带。

postmessage

HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。

otherWindow.postMessage(message, targetOrigin);
otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性;window.open的返回值;通过name或下标从window.frames取到的值。
message: 所要发送的数据,string类型。
targetOrigin: 用于限制otherWindow,”通配符”表示不作限制

a.com/index.html中的代码
1
2
3
4
5
6
7
8
9
<iframe id="ifr" src="b.com/index.html"></iframe>
<script>
window.onload = function() {
var ifr = document.getElementById('ifr');
var targetOrigin = 'http://b.com'; // 若写成'http://b.com/c/proxy.html'效果一样
// 若写成'http://c.com'就不会执行postMessage了
ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

b.com/index.html中的代码
1
2
3
4
5
6
7
8
9
10
<script>
window.addEventListener('message', function(event){
// 通过origin属性判断消息来源地址
if (event.origin == 'http://a.com') {
alert(event.data); // 弹出"I was there!"
alert(event.source); // 对a.com、index.html中window对象的引用
// 但由于同源策略,这里event.source不可以访问window对象
}
}, false);
</script>

CSS常见布局以及解决方案

发表于 2017-12-01 | 分类于 HTML与CSS |

整理了一下常见的基础布局以及对应的不同的解决方案

水平居中

margin + 定宽
1
2
3
4
5
6
7
8
9
10
<div class="parent">
<div class="child">Demo</div>
</div>

<style>
.child {
width: 100px;
margin: 0 auto;
}

</style>

table + margin
1
2
3
4
5
6
7
8
9
10
11
12
<div class="parent">
<div class="child">
Demo
</div>
</div>

<style>
.child {
display: table;
margin: 0 auto;
}

</style>

absolute + margin-left
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="parent">
<div class="child">
Demo
</div>
</div>

<style>
.parent {
position: relative;
}

.child {
position: absolute;
left: 50%;
width: 100px;
margin-left: -50px;
}

</style>

flex + justify-content
1
2
3
4
5
6
7
8
9
10
11
12
<div class="parent">
<div class="child">
Demo
</div>
</div>

<style>
.parent {
display: flex;
justify-content: center;
}

</style>

垂直居中

table-cell + vertical-align
1
2
3
4
5
6
7
8
9
10
11
12
<div class="parent">
<div class="child">
Demo
</div>
</div>

<style>
.parent {
display: table-cell;
vertical-align: middle;
}

</style>

absolute + transform
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="parent">
<div class="child">
Demo
</div>
</div>

<style>
.parent {
position: relative;
}

.child {
position: absolute;
top: 50%;
transform: translateY(-50%);
}

</style>

flex + align-items
1
2
3
4
5
6
7
8
9
10
11
12
<div class="parent">
<div class="child">
Demo
</div>
</div>

<style>
.parent {
display: flex;
align-items: center;
}

</style>

水平垂直居中

absolute + transform
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="parent">
<div class="child">
Demo
</div>
</div>

<style>
.parent {
position: relative;
}

.child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}

</style>

inline-block + text-align + table-cell + vertical-align
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="parent">
<div class="child">
Demo
</div>
</div>

<style>
.parent {
text-align: center;
vertical-align: middle;
display: table-cell;
}

.child {
display: inline-block;
}

</style>

flex + justify-content + align-items
1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="parent">
<div class="child">
Demo
</div>
</div>

<style>
.parent {
display: flex;
justify-content: center;
align-items: center;
}

</style>

一列定宽,一列自适应

float + margin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.left {
float: left;
width: 100px;
}

.right {
margin-left: 100px;
}

</style>

float + overflow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.left {
float: left;
width: 100px;
}

.right {
overflow: hidden;
}

</style>

table
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.parent {
display: table;
width: 100%;
table-layout: fixed;
}

.left {
display: table-cell;
width: 100px;
}

.right {
display: table-cell;
}

</style>

flex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.parent {
display: flex;
}

.left {
width: 100px;
margin-left: 20px;
}

.right {
flex: 1;
}

</style>

等分布局

float
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<div class="parent">
<div class="column">
<p>1</p>
</div>
<div class="column">
<p>2</p>
</div>
<div class="column">
<p>3</p>
</div>
<div class="column">
<p>4</p>
</div>
</div>

<style>
.parent {
margin-left: -20px;
}

.column {
float: left;
width: 25%;
padding-left: 20px;
box-sizing: border-box;
}

</style>

flex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<div class="parent">
<div class="column">
<p>1</p>
</div>
<div class="column">
<p>2</p>
</div>
<div class="column">
<p>3</p>
</div>
<div class="column">
<p>4</p>
</div>
</div>

<style>
.parent {
display: flex;
}

.column {
flex: 1;
}

.column+.column {
margin-left: 20px;
}

</style>

table
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<div class="parent-fix">
<div class="parent">
<div class="column">
<p>1</p>
</div>
<div class="column">
<p>2</p>
</div>
<div class="column">
<p>3</p>
</div>
<div class="column">
<p>4</p>
</div>
</div>
</div>

<style>
.parent-fix {
margin-left: -20px;
}

.parent {
display: table;
width: 100%;
table-layout: fixed;
}

.column {
display: table-cell;
padding-left: 20px;
}

</style>

圣杯布局(三列布局, 两边固定宽度中间自适应)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<div class="bd">
<div class="main">
</div>
<div class="sub">
</div>
<div class="extra">
</div>
</div>

<style>
.main {
float: left;
width: 100%;
}

.sub {
float: left;
width: 190px;
margin-left: -100%;
position: relative;
left: -190px;
}

.extra {
float: left;
width: 230px;
margin-left: -230px;
position: relative;
right: -230px;
}

.bd {
padding: 0 230px 0 190px;
}

</style>

补充:

  • DOM元素的顺序不能改变
  • 当main内容部分比两边的子面板宽度小的时候,布局就会乱掉。可以通过设置main的min-width属性或使用双飞翼布局避免问题

双飞翼布局(同三列,圣杯布局改进版)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div class="main-wrap column">
<div class="main">
#main
</div>
</div>
<div class="sub">
</div>
<div class="extra">
</div>

<style>
.main-wrap {
float: left;
width: 100%;
}

.sub {
float: left;
width: 190px;
margin-left: -100%;
}

.extra {
float: left;
width: 230px;
margin-left: -100%;
}

.main {
margin: 0 230px 0 190px;
}

</style>

以上为常见布局解决方案,传统主要用position, flex, table,float等属性去实现布局,另外就是flex相关一套弹性布局属性。还是觉得弹性布局的表达力更强,语法更直观实现更方便。另外在2017年末尾的今天,弹性布局的浏览器兼容问题也不算一个很大的问题了。

Mysql基础命令

发表于 2016-07-04 | 分类于 数据库 |

* 创建数据库

使用create database 语句创建数据库,命令格式如下:

create database 数据库名 [其他选项];

* 选择数据库

登陆后使用use语句指定

use 数据库名;

* 创建数据库表

使用create table 语句创建表,常见形式:

create table 表名称(列声明);

* 向表中插入数据

insert语句可以用来将一行或多行数据插入数据库表中,使用的一般形式如下:

insert [into] 表名 [(列名1,列名2,列名3,…)] values (值1,值2,值3…);

[]内容是可选的,例如要给samp_db数据库中students表插入一条记录,执行语句:

insert into students values(NULL, “王刚”, “男”,20, “1381137344”);

* 查询表中的数据

select语句常用来根据一定的查询规则到数据库中获取数据,基本用法为:

select 列名称 from 表名称 [查询条件];

若要查询students表中所有学生的名字和年龄,可以输入一下命令:

select name, age from students;

同时可以使用通配符查询表中所有内容,语句:select from students;

* 按特定条件查询

where关键词用于指定查询条件,用法形式为:

select 列名称 from 表名称 where 条件;

查询所有性别为女的信息:

select * from students where sex=”女”;

查询年龄在21岁以上的所有人信息:

select * from students where age > 21;

查询名字中带有”王”字的所有人的信息:

select * from students where name like “%王%”;

查询id小于5且年龄大于20的所有人信息:

select * from students where id < 5 and age > 20;

* 更新表中的数据

update语句可用来修改表中的数据,基本使用形式为:

update 表名称 set 列名称=新值 where 更新条件;

将id为5的手机号改为默认的”-“:

update students set tel=default where id=5;

将所有人的年龄增加1:

update students set age=age+1;

将手机号为13288097888的姓名改为”张维鹏“,年龄改为19:

update students set name=”张维鹏”, age=19 where tel=”13288097888”;

* 删除表中的数据

delete语句用于删除表中的数据,基本用法为:

delete from 表名称 where 删除条件;

使用示例:

  • 删除id为2的行:delete from students where id=2;
  • 删除所有年龄小于21岁的数据:delete from students where age<21;
  • 删除表中的所有数据: delete from students;

* 创建后表的修改

alter table 语句用于创建后对表的修改,基础用法如下:

添加列

alter table 表名 add 列名 列数据类型 [after 插入位置];

在表的最后追加列 address:

alter table students add address char(60);

修改列

基本形式:

alter table 表名 change 列名称 列新名称 新数据类型;

将表tel列修改为telphone:

alter table students change tel telphone char(13) default “-“;

删除列

基本形式:

alter table 表名 drop 列名称;

重命名表

基本形式:

alter table 表名 rename 新表名;

删除整张表

基本形式:

drop table 表名;

删除整个数据库

基本形式

drop database 数据库名;

双栈实现队列练习题

发表于 2016-06-21 | 分类于 Python |

任务描述:编写一个类,只能用两个栈结构实现队列,支持队列的基本操作(push,pop)。给定一个操作序列ope以及它的长度n,其中元素为正数代表push操作,为0代表pop操作,保证操作序列合法且一定含pop操作,请返回pop的结果序列。

输入:[1,2,3,0,4,0],6
返回:[1,2]

思路:push时正常的将元素push到第一个栈之中,当需要pop的时候,将第一个栈中的元素通通倒入第二个栈之中,此时第二个栈就与开始时第一个栈中元素顺序相反,然后对第二个栈进行pop操作,便实现了队列。

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class TwoStack:
def __init__(self):
self.push_stack = []
self.pop_stack = []

def push(self, item):
self.push_stack.append(item)

def pop(self):
for i in self.push_stack[::-1]:
self.pop_stack.append(i)
output = self.pop_stack.pop()
self.push_stack = self.pop_stack[::-1]
self.pop_stack = []
return output

def twoStack(self, ope, n):
# write code here
res = []
for i in ope:
if i > 0:
self.push(i)
elif i == 0:
res.append(self.pop())
return res

可查询最值的栈练习题

发表于 2016-06-21 | 分类于 Python |

任务描述:定义栈的数据结构,并在该类型中实现一个能够得到栈最小值,查询时间复杂度为O(1)的min函数。

思路:通过同时维护两个栈来实现,第一个栈为普通的栈,正常进栈出栈,第二个栈当push时若元素大于栈顶的元素,则跳过push,若元素小于或等于栈顶的元素,则正常push。当pop时,普通栈正常出栈,若pop出的元素等于第二个栈栈顶元素,则同样pop出第二个栈栈顶元素,否则跳过pop

Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution:
def __init__(self):
self.stack = []
self.min_stack = []

def push(self, node):
# write code here
self.stack.append(node)
if not self.min_stack:
self.min_stack.append(node)
elif node <= self.min_stack[-1]:
self.min_stack.append(node)

def pop(self):
# write code here
out = self.stack.pop()
if out == self.min_stack[-1]:
self.min_stack.pop()
return out

def top(self):
# write code here
return self.stack[-1]

def min(self):
# write code here
return self.min_stack[-1]
123
杨晨昊

杨晨昊

Stay hungry Stay foolish

29 日志
6 分类
14 标签
zhihu weibo
© 2018 杨晨昊
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.3