I'm PLDaily, a web developer from Hangzhou, China.
pldaily / blog Goto Github PK
View Code? Open in Web Editor NEW✨My Notes
✨My Notes
Generator很像是一个函数,但是你可以暂停它的执行。你可以向它请求一个值,于是它为你提供了一个值,但是余下的函数不会自动向下执行直到你再次向它请求一个值.
function* generateNaturalNumber() {
var i = 0;
while(i <= 5) {
yield i;
i++;
}
}
for(let i of generateNaturalNumber()) {
console.log(i);//0, 1, 2, 3, 4, 5
}
var test = generateNaturalNumber();
console.log(test.next());//{value: 0, done: false}
console.log(test.next());//{value: 1, done: false}
console.log(test.next());//{value: 2, done: false}
function test() {
var i = 0;
return {
next: function() {
return i <= 3 ? {value: i++, done: false} : {value: undefined, done: true};
}
}
}
var test = test();
console.log(test.next());//{value: 0, done: false}
console.log(test.next());//{value: 1, done: false}
console.log(test.next());//{value: 2, done: false}
console.log(test.next());//{value: 3, done: false}
console.log(test.next());//{value: undefined, done: true}
function *func() {
yield [2, 3, 4];
yield* [2, 3, 4];
}
for(let i of func()) {
console.log(i);
}
//[2, 3, 4]
//2
//3
//4
function* ticketGenerator(){
for(var i=0; true; i++){
var reset = yield i;
if(reset) {i = -1;}
}
}
var takeANumber = ticketGenerator();
console.log(takeANumber.next().value);//0
console.log(takeANumber.next().value);//1
console.log(takeANumber.next(true).value);//0
console.log(takeANumber.next(true).value);//0
console.log(takeANumber.next().value);//1
function delay(time, callback){
setTimeout(function(){
callback("Slept for "+time);
},time);
}
delay(1000,function(msg){
console.log(msg);
delay(1200,function(msg){
console.log(msg);
});
})
等待1s后出现"Slept for 1000",等待1.2s后出现"Slept for 1200"。
function delay(time, callback){
setTimeout(function(){
callback("Slept for "+time);
},time);
}
function* run(resume) {
yield delay(1000, resume);
yield delay(1200, resume);
}
function resume(msg) {
console.log(msg);
test.next()
}
var test = run(resume);
test.next();
等待1s后出现"Slept for 1000",等待1.2s后出现"Slept for 1200"。
一般的步骤网上有很多教程都进行了详细的讲解,在此不做复述,主要讲解一下自己在构建博客时遇到的问题及解决方案。
主要原因是由于__config.yml中deploy的配置
解决方案:
deploy:
type: git
repository: https://github.com/pcd12321/pcd12321.github.io.git
branch: master
1.安装
npm install hexo-deployer-git --save
2.将deploy 的 type由github改为git
主要有一下四种原因:
1.github仓库名必须与你的用户名相同
2.在git中输入指令时没有输入你的用户名与邮箱
3.需要等待十几分钟后网站才能正常运行
4.github给你发的邮箱没有打开验证
我是由于邮箱没有验证造成网页显示404
主题配置可以通过查看官网配置:NexT官网
在source目录下先删除该文章,再讲主目录下的db.json删除,使用命令hexo clean清除所有,在用hexo g构建,亲测有效。
注:public文件中的图片等一些在之前文章用到的需要先备份。
1._config.yml 中有 post_asset_folder:true
2.执行
npm install https://github.com/CodeFalling/hexo-asset-image --save
3.在文章的目录下新建一个文件夹images放入需要的文件
4.在文章中使用
![logo](images/bg1.jpg)
很久之前就一直想知道通过ajax加载且支持URL后退的博客的写法是如何实现,但由于当时的水平有限变放弃了。这几天在学习ng的时候想起了以前的这个问题,而且现在也学了许多的新知识,于是决定花些时间将其掌握。
<nav>
<a href="#/">Home</a>
<a href="#/blog">blog</a>
<a href="#/productos">productos</a>
</nav>
<section id="contenido" role="main">
</section>
我们新建三个导航栏,点击不同的导航通过ajax实现在#contenido中显示不同的内容。
我们通过点击导航获得不同的hash值,使ajax请求时发送不同的内容,从而让#contenido中显示不同的内容,我们将其放入函数getContent中
var getContent = function() {
var hash = window.location.hash;
if (hash == "#/") { load_page("Home"); } else
if (hash == "#/blog") { load_page("Blog"); } else
if (hash == "#/productos") {load_page("Productos"); }
}
load_page中的参数为发起ajax请求时发送的内容
load_page为ajax请求:
var load_page = function(inf){
$.ajax({
type: "GET",
url: "http://localhost:8080/test.php",
data: {page: inf},
cache: false,
success: function(result) {
$("#contenido").html(result);
}
});
}
<?php
echo $_GET['page'];
?>
当每次点击导航时将其href放置到history中,且要发起ajax请求
$("nav a").click(function() {
var href = $(this).attr("href");
history.pushState("", "", href);//ajax可前进后退
getContent();//执行ajax
});
window.onpopstate = function(event) {//点击前进后退时执行
getContent();
};
当该页面执行ajax操作后被保存,则在初始化时判断并执行
$(document).ready(function() {
getContent();//初始化页面
});
点击下载提取密码:sva7
npm install vuex --save
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
count: 0
}
const getters = {
count: state => state.count
}
组件中通过以下方式获取该状态值
computed: mapGetters([
'count'
])
const mutations = {
increment (state) {
state.count++
},
decrement (state) {
state.count--
}
}
const actions = {
increment: ({ commit }) => commit('increment'),
decrement: ({ commit }) => commit('decrement')
}
vue组件中通过以下方式调用
methods: mapActions([
'increment',
'decrement'
])
test.js
const state = {
count: 0
}
const getters = {
count: state => state.count
}
const mutations = {
increment(state) {
state.count++
},
decrement(state) {
state.count--
}
}
const actions = {
increment: ({ commit }) => commit('increment'),
decrement: ({ commit }) => commit('decrement')
}
export default {
state,
getters,
mutations,
actions
}
import test from './modules/test'
import test1 from './modules/test1'
import test2 from './modules/test2'
export default new Vuex.Store({
modules: {
test,
test1,
test2
}
})
import Vue from 'vue'
import Vuex from 'vuex'
import store from './vuex/store'
import App from './App.vue'
Vue.use(Vuex)
new Vue({
el: '#app',
store,
render: h => h(App)
})
vuex适用于在多个组件中均需用到某一状态的时候,例登陆状态,则需每一个组件均需使用。当某一状态仅仅需要特定的俩个组件之间使用时则不需要使用vuex。
<template>
<div>
<count :num="num" @changeNum="changeNum">
</count>
<button @click="addNum">按钮</button>
</div>
</template>
<script>
import Count from './count.vue'
export default {
data() {
return {
num: 0
}
},
components: {
Count
},
methods: {
addNum() {
this.num++;
},
changeNum(val) {
this.num = val;
}
}
}
</script>
<template>
<div>
{{num}}
<button @click="reset">重置</button>
</div>
</template>
<script>
export default {
props: ['num'],
methods: {
reset() {
this.$emit('changeNum', 0);
}
}
}
</script>
一直有想去看jquery源码的想法,但一直被网上的关于jquery源码很难的言论吓着了,迟迟没有行动。最近在公司写插件的时候发现自己在代码的架构上知识季度匮乏,一直想找一些代码学习与实践,遂决定看下jquery的源码。本章先记录一些jquery源码的静态属性与方法及一些好的代码书写规范。
(function(window) {
var $ = window.$;
var $ = 3;
window.$ = $;
})(window);
console.log($);//undefined
将全局的$指向局部的_$,在全局中$显示undefined
var class2Type = {
'[object Object]': 'object',
'[object Array]': 'array',
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object Function]': 'function',
'[object RegExp]': 'regexp',
'[object Date]': 'date',
'[object Error]': 'error',
'[object String]': 'string'
}
var toString = Object.prototype.toString;
function JStype(obj) {
return obj == null ? String(obj) : class2Type[ toString.call(obj) ] || 'object';
}
console.log(JStype({}));//object
console.log(JStype([1,2]));//array
console.log(JStype(true));//boolean
console.log(JStype(123));//number
console.log(JStype("123"));//string
console.log(JStype(function() {}));//function
console.log(JStype(new Date()));//date
console.log(JStype());//undefined
console.log(JStype(null));//null
console.log(JStype(undefined));//undefined
1.根据[object, class]对javascript的数据类型作出判断,前者的object表示对象的通用类,默认值;后者表示内部的对象类。
2.object为null与undefined可以直接作出判断,通过String转化为字符型。
3.toString不支持将null、undefined转化为字符型。
4.还可以通过obj + ""转化为字符型。
isNumber: function(obj) {
return !isNaN(parsentFloat(obj)) && isFinite(obj);
//通过parsentFloat将obj转化为数字,isNaN判断是不是非数字
}
isEmptyObject: function(obj) {
for(var name in obj) {
return false;
}
return true;
}
var aaa = '{"a": 123}';
console.log(JSON.parse(aaa));//{"a": 123}
console.log(eval("("+aaa+")"));//{"a": 123}
console.log((new Function("return " + aaa))());//{"a": 123}
var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
function trim( text ) {
return text == null ?
"" :
( text + "" ).replace( rtrim, "" );
}
var aaa = " aaaaaa";
console.log(aaa);//" aaaaaa"
console.log(trim(aaa));//"aaaaaa"
支持去除中文空格
function abc() {
var abc = [5,6];
console.log(arguments);
console.log(typeof arguments);
var args = Array.prototype.slice.apply(arguments);//转化为数组
console.log(arguments.cancat(abc));//error
console.log(args.concat(abc));//[1,2,3,4,5,6];
}
abc(1,2,3,4);
function isArray(elem, array) {
//局部变量的定义全部放开头
var len, i = 0,
indexOf = Array.prototype.indexOf;
if(array) {
if(indexOf) {
return indexOf.call(array, elem, i);
}
len = array.length;
for( ; i < len; i++) {
if(i in array && array[i] == elem) {
return i;
}
}
}
return -1;
}
console.log(isArray(4, [1,2,3,4,5]));//3
function merge(first, second) {
var len = second.length,
j = 0,
i = first.length;
for ( ; j < len; j++ ) {
first[ i++ ] = second[ j ];
}
first.length = i;
return first;
}
console.log(merge([1,2,3],[4,5,6]));//[1,2,3,4,5,6]
(function(win) {
var global = win;
var doc = global.document;
var dom = function(params, context) {
return new GetOrMakeDom(params, context);
}
var GetOrMakeDom = function(params, context) {
var currentContext = doc;
if(context) {
if(context.nodeType) {
currentContext = context;
}else {
currentContext = doc.querySelector(context);
}
}
if(!params || params === '' || typeof params === 'string' && params.trim() === '') {
this.length = 0;
return this;
}
if(typeof params === 'string' && /^\s*<(\w+|!)[^>]*>/.test(params)) {
var divElm = currentContext.createElement('div');
divElm.className = 'doc-frag-wrapper';
var docFrag = currentContext.createDocumentFragment();
docFrag.appendChild(divElm);
var queryDiv = docFrag.querySelector('div');
queryDiv.innerHTML = params;
var numberOfChildren = queryDiv.children.length;
for(var i = 0; i < numberOfChildren; i++) {
this[i] = queryDiv.children[i];
}
this.length = numberOfChildren;
return this;
}
if(typeof params === 'object' && params.nodeName) {
this.length = 1;
this[0] = params;
return this;
}
var nodes;
if(typeof params !== 'string') {
nodes = params;
}else {
nodes = currentContext.querySelectorAll(params.trim());
}
var nodeLength = nodes.length;
for(var i = 0; i < nodeLength; i++) {
this[i] = nodes[i];
}
this.length = nodeLength;
return this;
}
global.dom = dom;
dom.fn = GetOrMakeDom.prototype;
})(window)
dom.fn.each = function(callback) {
var len = this.length;
for(var i = 0; i < len; i++) {
callback.call(this[i], i, this[i]);
}
return this;
}
dom.fn.html = function(htmlStringOrTextString) {
if(htmlStringOrTextString) {
return this.each(function() {
this.innerHTML = htmlStringOrTextString;
})
}else {
return this[0].innerHTML;
}
}
dom.fn.text = function(textString){
if(textString){
return this.each(function(){
this.textContent = textString;
});
}else{
return this[0].textContent.trim();
}
};
dom.fn.append = function(stringOrObject) {
return this.each(function() {
if(typeof stringOrObject === 'string') {
this.insertAdjacentHTML('beforeend', stringOrObject);
}else {
var that = this;
dom(stringOrObject).each(function(name,value){
that.insertAdjacentHTML('beforeend',value.outerHTML);
});
}
})
}
vue.js1.0
<input v-on:keyup.13="submit">
vuejs2.0
Vue.config.keyCodes.f1 = 112;
<input v-on:keyup.f1="submit">
示例
https://jsfiddle.net/pcd12321/w83deoo0/
vue.js1.0
create -> beforeCompile -> compiled -> ready -> beforeDestroy -> destroyed
vuejs2.0
beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeDestroy -> destroyed
vuejs1.0
{{{html}}}
vuejs2.0
<div v-html="html"></div>
示例
https://jsfiddle.net/pcd12321/8ayeu77d/
使用emit与on的方法
https://jsfiddle.net/pcd12321/650rsgna/2/
该方法为通用方法,既可以用于子级监听父级,也可以用于父级监听子级
父级监听子级事件变化还可通过以下方式实现
https://jsfiddle.net/pcd12321/rbq1n4ps/4/
子级监听父级事件变化可以使用prop但当使用路由时,多个路由中只有一个需要用到父组件中的message,则此时使用prop便不是很好的方法,一般使用事件广播。
创建实例时传递 props。主要作用是方便测试。
示例
https://jsfiddle.net/pcd12321/1qc3d21L/
html只渲染一次
https://jsfiddle.net/pcd12321/chzkk4c8/6/
示例
https://jsfiddle.net/pcd12321/emrzdrvy/
本文记录了通过实际代码演示node中的事件轮询及轮询中的回调函数的执行方式
User.get = function(name, callback) {
console.log(44);
//以下为省略数据库读取操作,读取成功后执行回调函数callback
}
User.test = function(callback) {
console.log(55);
callback();
}
User.test2 = function(callback) {
console.log(66);
callback();
}
User.get("pcd", function(err, user) {
console.log(11);
});
User.test(function() {
console.log(22);
});
User.test2(function() {
console.log(33);
})
以上代码执行的结果为44,55,22,66,33,11。
由以上代码可知node采用的是非阻塞的I/O机制,不会在程序结束之前阻碍其他处理的进行,在程序处理结束的时候调用回调函数。
本文记录了一些node.js中的Buffer模块的学习笔记,基于最新的文档v6.9.1.
var buffer1 = new Buffer('Hello World');//老方法
var buffer2 = new Buffer('48656c6c6f204e6f6465', 'hex');//老方法
var buffer3 = new Buffer(1024);//老方法
var buffer4 = Buffer.from('Hello World');//新方法
var buffer5 = Buffer.from('48656c6c6f204e6f6465', 'hex');//新方法
var buffer6 = Buffer.alloc(1024);//新方法
var buffer1 = Buffer.alloc(5);//对原数据进行覆盖
var buffer2 = Buffer.allocUnsafe(5;//还存在原数据,速度更快,通过pool分配内存
var buffer3 = Buffer.allocUnsafeSlow(5);//通过c++分配内存
buffer1相当于buffer2.fill(0)
var buffer = Buffer.allocUnsafe(5);
console.log(buffer);//buffer中存在原数据
console.log(buffer.toString());
buffer.write('Hello');
console.log(buffer.toString());//Hello
buf.write(string[, offset[, length]][, encoding])的参数
var buffer = Buffer.from('Hello World');
console.log(Buffer[3]);//l
console.log(buffer.toString());//Hello
buffer[3] = 109;
console.log(buffer.toString());//Helmo
var buffer1 = Buffer.from('Hello World');
console.log(buffer1.toString());//Hello World
console.log(buffer1.toString('hex'));//48656c6c6f204e6f6465
console.log(buffer1.toString('base64'));//SGVsbG8gV29ybGQ=
var buffer2 = Buffer.from('48656c6c6f204e6f6465', 'hex');
console.log(buffer2.toString());//Hello World
var buffer3 = Buffer.from('SGVsbG8gV29ybGQ=', 'base64');
console.log(buffer3.toString());//Hello World
var buffer = Buffer.from('Hello World');
var buffer1 = buffer.slice(2, 5);
console.log(buffer1.toString());//llo
var longBuffer = Buffer.from('this is a long Buffer');
var smallBuffer = Buffer.alloc(5);
longBuffer.slice(5, 10).copy(smallBuffer, 0, 0, 5);//从smallBuffer的第1位开始写入longBuffer.slice(5, 10)的第1到第5位
console.log(smallBuffer.toString());//is a
本文记录了一些node.js中的async中间件的学习笔记。
async.series({
one: function(callback) {
callback(null, 1);
},
two: function(callback) {
callback(null, 1);
}
}, function(err, results) {
console.log(results);//{one: 1, two: 1}
})
function async(arg, callback) {
console.log('do something with \''+arg+'\', return 1 sec later');
setTimeout(function() { callback(arg * 2); }, 1000);
}
function final() { console.log('Done', results); }
var items = [ 1, 2, 3, 4, 5, 6 ];
var results = [];
function series(item) {
if(item) {
async( item, function(result) {
results.push(result);
return series(items.shift());
});
} else {
return final();
}
}
series(items.shift());
async.waterfall([
function(callback){
callback(null, 'one', 'two');
},
function(arg1, arg2, callback){
// arg1 now equals 'one' and arg2 now equals 'two'
callback(null, 'three');
},
function(arg1, callback){
// arg1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
// result now equals 'done'
console.log(result);
});
async.parallel([
function(callback){
callback(null, 'one');
},
function(callback){
callback(null, 'two');
}
],
function(err, results){
console.log(results);//['one', 'two']
});
async.parallelLimit([
function(callback){
callback(null, 'one');
},
function(callback){
callback(null, 'two');
},
function(callback){
callback(null, 'one');
},
function(callback){
callback(null, 'two');
},
function(callback){
callback(null, 'one');
}
],
2,
function(err, results){
console.log(results);
})
function async(arg, callback) {
console.log('do something with \''+arg+'\', return 1 sec later');
setTimeout(function() { callback(arg * 2); }, 1000);
}
function final() { console.log('Done', results); }
var items = [ 1, 2, 3, 4, 5, 6 ];
var results = [];
var running = 0;
var limit = 2;
function launcher() {
while(running < limit && items.length > 0) {
var item = items.shift();
async(item, function(result) {
results.push(result);
running--;
if(items.length > 0) {
launcher();
} else if(running == 0) {
final();
}
});
running++;
}
}
本文记录了一些node.js中的fs模块的学习笔记,基于最新的文档v6.9.1。
var fs = require('fs');
//返回的信息包括文件的大小、创建的日期等信息
fs.stat('./test/test.js', function(err, stats) {
//返回的信息包括文件的大小、创建的日期等信息
console.log(stats);
//stats.isFile()判断是否是标准文件
console.log(stats.isFile());//true
//stats.isDirectory()判断是否是目录
console.log(stats.isDirectory());//false
if(stats&&stats.isFile()) {
console.log('文件存在');
}else {
console.log('文件不存在或不是标准文件');
}
})
fs.F_OK - 文件是对于进程是否可见,可以用来检查文件是否存在
fs.R_OK - 文件对于进程是否可读
fs.W_OK - 文件对于进程是否可写
fs.access('./test/test.js', fs.F_OK, function(err) {
if(err) {
console.log('文件不存在');
}else {
console.log('文件存在');
}
})
fs.access('./test/test.js', fs.R_OK | fs.W_OK, function(err) {
if(err) {
console.log('不可读写');
}else {
console.log('可读或写');
}
})
var fs = require('fs');
fs.stat('./test/test.js', function(err, stats) {
if(stats.isFile()) {
//r打开文本进行读取操作,数据流位置在文件起始处
//r+打开文本进行读写操作,数据流位置在文件起始处
//w打开文件进行写入,如果文件存在,将其清零,不存在创建写入文件,数据流位置在文件起始处
//w+打开文件进行读写,w如果文件存在,将其清零,不存在创建写入文件,数据流位置在文件起始处
//a打开文件进行写入,如果文件存在,将其清零,不存在创建写入文件,数据流位置在文件结尾处
//a+打开文件进行读写,w如果文件存在,将其清零,不存在创建写入文件,数据流位置在文件结尾处
fs.open('./test/test.js', 'r', function(err, fd) {
})
}
})
var fs = require('fs');
fs.stat('./test/test.js', function(err, stats) {
if(stats.isFile()) {
fs.open('./test/test.js', 'r', function(err, fd) {
var buffer = Buffer.alloc(1024);
var offset = 0;//buffer存储开始的位置
var len = buffer.length;
var filePosition = 0;//文件开始读取的位置
fs.read(fd, buffer, offset, len, filePosition, function(err, readByte) {
console.log('读取数据总数:'+readByte+' bytes' );
console.log(buffer);
console.log(buffer.slice(0, readByte)); //数据已被填充到readBuffer中
})
})
}
})
fs.readFile('./test/test.js', function(err, data) {
console.log(data.toString());
})
fs.read可用于读取部分内容,而fs.readFile只能读取全部内容
var fs = require('fs');
fs.stat('./test/test.js', function(err, stats) {
if(stats.isFile()) {
fs.open('./test/test.js', 'a', function(err, fd) {
var buffer = Buffer.from("Hello World");
var offset = 0;//buffer开始写入的位置
var len = buffer.length;
var filePosition = null;//文件写入的位置
fs.write(fd, buffer, offset, len, filePosition, function(err, writeByte) {
console.log('写入数据总数:'+writeByte+' bytes' );
})
})
}
})
var fs = require('fs');
fs.open('./test/test.js', 'r', function(err, fd) {
//对文件的一些操作
fs.close(fd, function(err) {
console.log(err);
})
})
var fs = require('fs');
s.stat('./test/test.js', function(err, stats) {
if(stats.isFile()) {
fs.unlink('./test/test.js');
}
})
var fs = require('fs');
fs.readdir('./', function(err, files) {
console.log(files);//['main.js', 'test']
})
var fs = require('fs');
var path = require('path');
fs.mkdir(path.join(__dirname, './test1'), function(err) {
fs.readdir('./', function(err, files) {
console.log(files);//['main.js', 'test', 'test1']
})
})
var fs = require('fs');
var path = require('path');
fs.rmdir(path.join(__dirname, './test1'), function(err){
fs.readdir('./', function(err, files) {
console.log(files);//['main.js', 'test']
})
})
var fs = require('fs');
fs.rename('./test/test.js', './test1.js', function(err) {
console.log('移动与重命名成功');
})
var fs = require('fs');
readStream.on('open', function(fd) {
console.log('文件已打开');
})
readStream.on('data', function(data) {
console.log('收到文件数据');
console.log(data.toString());
})
var writeStream = fs.createWriteStream('./test/test.js');
var buffer = Buffer.from("PCD");
writeStream.write(buffer);
window.throttle = function(func, wait, options) {
var context, args, result;
var timer = null;
var previous = 0;
if(!options) options = {};
var later = function() {
previous = new Date().getTime();
timer = null;
result = func.apply(context, args);
context = args = null;
}
return function() {
var now = new Date().getTime();
if(!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if(remaining <= 0) {
if(timer) {
clearTimeout(timer);
timer = null;
}
previous = now;
result = func.apply(context, args);
context = args = null;
}else if(!timer && options.trailing !== false) {
timer = setTimeout(later, remaining);
}
return result;
}
}
window.addEventListener('scroll', _.throttle(abc, 500, {leading: false, trailing: true}));
func | wait | options |
---|---|---|
需要执行的函数 | 多少时间内不重复执行该函数 | 可选参数 |
leading | trailing |
---|---|
触发事件前是否先执行一次函数 | 最后一次在wait时间内的函数是否执行 |
在wait内只执行一次函数
throttle 策略的电梯。保证如果电梯第一个人进来后,15秒后准时运送一次,不等待。如果没有人,则待机。
window.debounce = function(func, wait, immediate) {
var timer, args, context, timestamp, result;
var later = function() {
var last = new Date().getTime() - timestamp;
if(last < wait && last > 0) {
timer = setTimeout(later, wait - last);
}else {
timer = null;
if(!immediate) {
result = func.apply(context, args);
context = args = null;
}
}
}
return function() {
context = this;
args = arguments;
timestamp = new Date().getTime();
var callNow = immediate && !timer;
if(!timer) timer = setTimeout(later, wait);
if(callNow) {
result = func.apply(context, args);
context = args = null;
}
return result;
}
}
window.addEventListener('scroll', _.debounce(abc, 500, true))
func | wait | immediate |
---|---|---|
需要执行的函数 | 多少时间内不执行该函数 | 可选参数 |
true | false |
---|---|
在wait事件内多次触发事件以第一次为准 | 在wait事件内多次触发事件以最后一次为准 |
在wait内连续点击以第一次或最后一次为准,wait时间内再次点击则wait时间重新开始计时。
debounce 策略的电梯。如果电梯里有人进来,等待15秒。如果又人进来,15秒等待重新计时,直到15秒超时,开始运送。
本文记录了一些node.js中的url模块的学习笔记,基于最新的文档v6.9.1.
var url = require('url');
var urlString = "http://user:[email protected]:8080/p/a/t/h?query=string#hash";
console.log(url.parse(urlString));
/*{
"protocol":"http:",
"slashes":true,
"auth":"user:pass",
"host":"host.com:8080",
"port":"8080",
"hostname":"host.com",
"hash":"#hash",
"search":"?query=string",
"query":
"query=string",
"pathname":"/p/a/t/h",
"path":"/p/a/t/h?query=string",
"href":"http://user:[email protected]:8080/p/a/t/h?query=string#hash"
}
*/
var url = require('url');
var urlJson = {
"protocol":"http:",
"slashes":true,
"auth":"user:pass",
"host":"host.com:8080",
"port":"8080",
"hostname":"host.com",
"hash":"#hash",
"search":"?query=string",
"query":
"query=string",
"pathname":"/p/a/t/h",
"path":"/p/a/t/h?query=string",
"href":"http://user:[email protected]:8080/p/a/t/h?query=string#hash"
}
console.log(url.format(urlJson));//"http://user:[email protected]:8080/p/a/t/h?query=string#hash"
.parent p:first-child {
color:green;
}
.parent p:last-child {
color: red;
}
.parent p:nth-child(1) {
color:yellow;
}
.parent p:nth-last-child(1) {
color:blue;
}
.parent p:first-of-type {
color:green;
}
.parent p:last-of-type {
color:red;
}
.parent p:nth-of-type(2) {
color:yellow;
}
.parent p:nth-last-of-type(2) {
color:blue;
}
.parent p:not(.first) {
color: red;
}
.parent > p:first-child {
color: red;
}
ASCLL: 上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。
ASCII码一共规定了128个字符的编码,比如空格"SPACE"是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0
Unicode: 将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储,不同标准占的字节数不同(大于1字节)
UTF-8: UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
UTF-8的编码规则很简单,只有二条:
英文在unicode中占2-4个字节(不同标准占的字节数不同,总之大于1字节),但utf-8中占一个字节
Unicode | UTF-8 |
---|---|
0000 0000-0000 007F | 0xxxxxxx |
0000 0080-0000 07FF | 110xxxxx 10xxxxxx |
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
UTF-16:就是任何字符对应的数字都用两个字节来保存.但是很显然如果都是英文字母这做有点浪费,但汉字在utf-16中占2个字节,但在utf-8中可能占3个字节。
JS中字符以UTF-16的格式存储,每个字符为为2个字节,可存字符为2^8*2^8个字符,但超出这个范围即Unicode编码大于65536,则通过四个字节存储。 以古文"𣦵"为例,Unicode值为145845,大于65536,以4个字节存储。 现有的charAt、charCodeAt只能处理Unicode编码范围内的字符,ES6引入codePointAt方法
var s = "𣦵";
console.log(s.codePointAt(0));//145845
charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数
函数 | 描述 |
---|---|
decodeURI() | 解码某个编码的 URI。 |
decodeURIComponent() | 解码一个编码的 URI 组件。 |
encodeURI() | 把字符串编码为 URI。 |
encodeURIComponent() | 把字符串编码为 URI 组件。 |
escape() | 对字符串进行编码。(以弃用) |
unescape() | 对由 escape() 编码的字符串进行解码。(以弃用) |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>编码/解码</title>
</head>
<body>
<script type="text/javascript">
var test = "http://www.test.com/My test/";
var test1 = encodeURI(test);
var test2 = decodeURI(test1);
var test3 = encodeURIComponent(test);
var test4 = decodeURIComponent(test3);
console.log(test1);/*
http://www.test.com/My%20test/
*/
console.log(test2);/*
http://www.test.com/My test/
*/
console.log(test3);/*
http%3A%2F%2Fwww.test.com%2FMy%20test%2F
*/
console.log(test4);/*
http://www.test.com/My test/
*/
</script>
</body>
</html>
特点:唯一,无序性
SADD key number [member ...]
SADD letters a b c
SREM key number [member ...]
SREM letters a c
SMEMBERS key
SMEMBERS letters
SCARD key
SCARD letters
SISMEMBER key member
SISMEMBER letters a
SRANDMEMBER key [count]
SRANDMEMBER letter 2 // 从集合中获取2个元素(不重复)
SRANDMEMBER letter -2 // 从集合中获取2个元素(可能重复)
SPOP key
SMEMBERS letters // a b c d
SPOP letters //随机选中b
SMEMBERS letters //a c d
SDIFF key [key ...]
SADD setA 1 2 3
SADD setB 2 3 4
SDIFF setA setB //1
SDIFF setB setA //4
SADD setA 1 2 3
SADD setB 2 3 4
SINTER setA setB //2 3
SADD setA 1 2 3
SADD setB 2 3 4
SUNION setA setB //1 2 3 4
特点: 有序
ZADD key score member [score member ...]
ZADD key scoreboard 89 Tom 67 Peter 100 David
ZSCORE key member
ZSCORE scoreboard Tom
ZRANGE key start stop [WITHSCORES]
ZRANGE scoreboard 0 2 //从0开始,只获取可以值
ZRANGE scoreboard 0 -1 //-1表示最后一个元素,只获取key值
ZRANGE scoreboard 0 2 WITHSCORES //获取key与value值
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
ZRANGEBYSCORE scoreboard 80 100 //大于等于80,小于等于100
ZRANGEBYSCORE scoreboard 80 (100 //大于等于80,小于100
ZRANGEBYSCORE scoreboard (80 +inf //大于80,+inf为正无穷
ZRANGEBYSCORE scoreboard 60 +inf LIMIT 1 3 //分数高于60分的从第二个人开始的3个人
ZINCRBY key increment member
ZINCRBY scoreboard -4 Tom
<div id="home" style="width: 100px; height: 100px; background-color: red;">
<div id="div1" style="width: 50px; height: 50px; background-color: green;">
</div>
</div>
var oHome = document.getElementById("home");
oHome.onmouseenter = function() {
console.log('enter');
}
var oHome = document.getElementById("home");
oHome.onmouseover = function() {
console.log('over');
}
当鼠标移入子元素#div1时,onmouseover事件会冒泡到父元素从而触发事件,而onmouseenter不会发生事件冒泡。
关于前端的跨域问题一直都想去了解应该如何去解决,但由于没有实际例子,看了网上的很多例子一直都处于懵懂的状态,正好公司最近出了一个跨域的问题就随便学习总结了一下。
情景说明:俩个子域名一个biz,一个user_center,后台使用thinkphp的框架,biz下的一个用户反馈的邮箱的方法写在user_center项目中,当点击邮箱要发送电子邮件的时候就涉及到了跨域。由于jquery的跨域只支持get的方式,不支持post,本文主要讲解jquery的get方式的跨域处理
$.ajax({
type: 'get', //请求的方式
url: 'http://user.cli.me/service/index/send',//请求的地址
data: data,//传输的数据
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'abc',
success:function(ret){
//成功后的操作
}
});
脚本在biz.cli.me的页面下,对user.cli.me的页面发起一个异步请求
public function send(){
//对传过来data数据的处理操作省略
$this->_ajax(1,'发送成功',4);
}
private function _ajax($status=null,$msg=null,$data=null){
$arr['status'] = $status;
$arr['data'] = $data;
$arr['msg'] = $msg;
if(isset($_GET['callback'])) {
$callback = GET("callback");//获取callback,相当于客户端与服务端的一个通信
$json = $this->_json($arr);
$jsonp = $callback.'(' . $json . ')';
echo $jsonp;
}else {
echo $this->_json($arr);
}
exit;
}
//转化成JSON数据
private function _json($arr){
if(is_array($arr)) return json_encode($arr);
}
后台先是通过get获取前台的callback,形成前台与后台的通信。再是对需要返回的数据进行处理,使用jsonp形式输出。
abc({"status":1,"data":4,"msg":"\u53d1\u9001\u6210\u529f"});
该数据只是示例,可以按自己的实际需求输出
success: function(ret) {
console.log(ret);//{status: 1, data: 4, msg: "发送成功"}
}
在向github提交代码时发现github不记录commit为contributions。发现是因为commits使用的name与email地址是与你的Github账号不符。通过以下命令行进行设置
$ git config --global user.name "PLDaily"//github的用户名
$ git config --global user.email "[email protected]" //github相关联的邮箱
LoadModule rewrite_module modules/mod_rewrite.so
修改.htaccess中的内容中的对应代码为
RewriteEngine On
RewriteCond %{THE_REQUEST} \s/+index.php?([^\s&]+) [NC]
RewriteRule ^ %1? [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/?$ index.php?$1 [L,QSA]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
#div1 {
width: 500px;
height: 200px;
background: yellow;
text-align: center;
}
#div2 {
width: 100px;
height: 100px;
background-color: red;
display: inline-block;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2">
</div>
</div>
</body>
</html>
将红块div设置为内联块元素,黄块div设置text-align,此时的红块居于黄块中间。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
#div1 {
width: 500px;
height: 200px;
background: yellow;
text-align: center;
position: relative;
}
#div2 {
position: absolute;
width: 100px;
height: 100px;
background-color: red;
display: inline-block;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2">
</div>
</div>
</body>
</html>
此时的红块左边框处于居中位置,并不是红块整体居中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
#div1 {
width: 500px;
height: 200px;
background: yellow;
text-align: center;
position: relative;
}
#div2 {
position: relative;
width: 100px;
height: 100px;
background-color: red;
display: inline-block;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2">
</div>
</div>
</body>
</html>
红块整体处于居中位置。
造成以上的原因是由于绝对定位使元素脱离文档流。
后端提供数据接口,前端实现数据展示及交互
vue属于MVVM,jquery属于MVC
MVC: view-Controller-Model
View: 用于展示数据
Model: 用于管理数据
Controller: 响应用户操作,并将Model更新到View上
Controller层上要进行事件绑定,响应用户操作,更新View等事务,jquery就是为了方便这些操作应运而生
缺点:
1.开发者处理大量的DOM API,处理繁琐,代码难以维护
2.大量DOM操作使页面渲染性能降低,影响用户体验
3.MOdel频繁更改,开发者需要主动更新到View层,用户操作影响Model层数据,用户需要将数据同步,十分繁琐
MVVM: Model-View-ViewModel
Model: 代表数据
View: 数据模型转化成UI展现出来
ViewModel: 同步View 和 Model的对象
ViewModel通过双向数据绑定把View层和Model层,
开发者不需要过多关注数据同步问题,不需要手动操作DOM。只需关注业务逻辑
ReactDOM.render(
<h1>Hello World</h1>,
document.getElementById('root')
);
var App = <h1>Hello World</h1>
ReactDOM.render(
App,
document.getElementById('root')
);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<h1>Hello World</h1>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
var App = React.createClass({
getInitialState: function() {
return {}
},
render: function() {
return (
<h1>Hello World</h1>
)
}
})
ReactDOM.render(
<App />,
document.getElementById('root')
);
本文记录了一些node.js中的path模块的学习笔记,基于最新的文档v6.9.1.
console.log(path.basename('/foo/bar/baz/asdf/quux.html'));
// returns 'quux.html'
console.log(path.basename('/foo/bar/baz/asdf/quux.html', '.html'));
// returns 'quux'
console.log(path.basename('/foo/bar/baz/asdf/quux.html', '.js'));
// returns 'quux.html'
path.basename()方法可以提取出一个文件路径中的文件的部分。第二个参数为可选扩展名,指定扩展名则只返回文件名,指定扩展名不合法时将返回文件全名
console.log(path.dirname('/foo/bar/baz/asdf/quux'));
// returns '/foo/bar/baz/asdf'
path.dirname()方法可以提取出一个文件路径中的目录的部分
console.log(path.extname('index.html'));
// returns '.html'
console.log(path.extname('index.coffee.md'));
// returns '.md'
console.log(path.extname('index.'));
// returns '.'
console.log(path.extname('index'));
// returns ''
console.log(path.extname('.index'));
// returns ''
path.extname()方法可以提取文件的扩展名
console.log(path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'));
// returns '/foo/bar/baz/asdf'
path.join()方法可以连接任意多个路径字符串
console.log(path.normalize('/foo/bar//baz/asdf/quux/..'));
// returns '/foo/bar/baz/asdf'
path.normalize()方法对路径进行规范化处理
console.log(path.parse('/home/user/dir/file.txt'));
// returns
// {
// root : "/",
// dir : "/home/user/dir",
// base : "file.txt",
// ext : ".txt",
// name : "file"
// }
path.parse()方法对路径进行解析
console.log(path.format({
root : "C:\\",
dir : "C:\\path\\dir",
base : "file.txt",
ext : ".txt",
name : "file"
}));
//returns c:\path\dir\file.txt
path.format()从对象返回一个字符串,与path.parse()相反
console.log(path.resolve('/foo/bar', './baz'));
// returns '/foo/bar/baz'
console.log(path.resolve('/foo/bar', '/tmp/file/'));
// returns '/tmp/file'
path.resolve()方法可以将多个路径解析为一个规范化的绝对路径
console.log(path.relative('C:\\orandea\\test\\aaa', 'C:\\orandea\\impl\\bbb'));
// returns '..\\..\\impl\\bbb'
path.relative()方法可以找出一个绝对路径到另一个绝对路径的相对关系,从前者的路径去找后者
console.log(path.isAbsolute('/foo/bar')); // true
console.log(path.isAbsolute('/baz/..')); // true
console.log(path.isAbsolute('qux/')); // false
path.isAbsolute()方法判断路径是否是绝对路径
本文记录了一些node.js中的request模块的学习笔记。
request('https://www.baidu.com').pipe(fs.createWriteStream('aaa.html'));
request
.get('http://itbilu.com/images/logo.png')
.on('error', function(err) {
console.log(err);
})
.on('response', function(response) {
console.log(response.statusCode);
console.log(response.headers['content-type']);
})
.pipe(fs.createWriteStream('doodle.png'));
http.createServer(function(req, res) {
request.get('https://baidu.com').pipe(res);
}).listen(3000);
http.createServer(function(req, res) {
console.log(req.method);
if(req.url == '/images/logo.png') {
var x = request('http://itbilu.com/images/logo.png');
req.pipe(x);
x.pipe(res);
}
}).listen(3000);
var formData = {
file1: fs.createReadStream(__dirname + '/doodle.png'),
};
//localhost:3000是本地搭建的一个express博客的地址,用于表单提交测试
request.post({url:'http://localhost:3000/upload', formData: formData}, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
undefined、null、String、Number、Boolean按值传递
当一个变量像另一个变量复制引用类型的值时,同样也会将存储在变量中的值复制一份放到为新变量分配的空间中,不同的是,这个值的副本实际是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,俩个变量实际上引的是同一个对象。
var a = 1;
b = a;
a = 2;
console.log(a)//2
console.log(b);//1
var c = {
a: 1
}
var d = c;
c = {
a: 2
}
console.log(c.a);//2
console.log(d.a);//1
function abc() {
this.a = 1;
}
var e = new abc();
var f = e;
e.a = 2;
console.log(f.a);//2
web客户端存储主要包括cookie、localStorage与sessionStorage。本文详细介绍三者之前的区别。
cookie的名/值中的值不允许包含分号、逗号和空白号,采用encodeURIComponent对值进行编码,decodeURIComponent进行解码
key:名
value:值
path:路径
expires:过期时间(该属性有HTTP1.0定义,支持IE8。max-age为HTTP1.1定义,不支持IE8)
function setCookie(name, value, expires, path) {
document.cookie =name + '=' + encodeURIComponent(value) + ';expires = ' + expires + ';path = ' + path;
}
setCookie("name", "pcd", 1000*60*60, '/');
function getCookie(key) {
var all = document.cookie;
var list = all.split(';');
if(all === '') {
return cookie;
}
for(var i = 0; i < list.length; i++) {
var cookie = list[i].trim();//去除空白字符
var p = cookie.indexOf('=');
var name = cookie.substring(0, p);
if(name == key) {
var value = cookie.substring(p + 1);
value = decodeURIComponent(value);
return value;
}
}
return false;
}
console.log(getCookie('name'));//pcd
因为每一次HTTP请求会把这些数据传输到服务器,所以浏览器对每个cookie的保存数据不能超过4k。
window.addEventListener('storage', function(e) {
console.log(e.key + "--" + e.newValue + "--" + e.oldValue + "--" + e.storageArea + "--" + e.url);
}, true)
使用示例:一个基于WEB的图片编辑应用,通常允许其他窗口展示工具条。当用户选择一个工具时,应用使用localStorage存储当前状态,便可通知其他窗口用户选择了新工具(其他窗口通过存储事件监听)。
在看jquery源码时遇到一些关于对象的问题,决定再回去学习巩固一下对象的基础。
创建构造函数,从而自定义对象类型的属性和方法。构造函数始终都应以一个大写字母开头,该做法借鉴自其它OO语言,为了区别与其他函数。我们使用new操作符,创建一个实例。每创建一个实例,构造函数内的方法就都要在每个实例上重新创建一遍,但俩个方法不是同一个Function实例。
function Person(name) {
this.name = name;
this.sayName = function() {
console.log(this.name);
}
}
var person1 = new Person('aaa');
var person2 = new Person('bbb');
console.log(person1.sayName == person2.sayName);//false
所以我们需要使用原型共享一些属性与方法
javascript中每一个函数都有一个原型属性,prototype就是通过调用构造函数创建的那个对象实例的原型。使用原型对象可以让所有的对象实例共享它所有的属性和方法。
function Person(name) {}
Person.prototype.name = "aaa";
Person.prototype.sayName = function() {
console.log(this.name);
}
var person1 = new Person();
var person2 = new Person();
console.log(person1.sayName == person2.sayName);//true
每个函数都有一个原型属性,这个属性指向函数的原型对象
__proto__存在于实例与构造函数的原型对象之间
原型对象中的constructor属性指向构造函数
构造函数中的this指向实例
通过以上的属性,我们可以直接实现new操作符
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
console.log(this.name);
}
var person1 = {};
person1.__proto__ = Person.prototype;
Person.call(person1, "aaa");
person1.sayName();//aaa
当代码读取某个对象的某个属性时,从对象本身开始,到构造函数内部,再到原型去获取。相同的属性会屏蔽其他相同的属性,其他相同的属性并不会消失。
function Person() {
this.name = "aaa";
}
Person.prototype.name = "bbb";
var person1 = new Person();
person1.name = "ccc";
console.log(person1.name);//"ccc"
通过对象字面来重写原型对象会将原来的原型对象覆盖,导致原来的原型对象的constructor指向构造函数被新的原型对象所替换,指向了Object。所以需要在对象字面量中添加constructor属性指向构造函数。
function abc() {
this.aaa = 1;
}
abc.prototype.bbb = 2;
abc.prototype = {
constructor: abc,
"ccc": 3,
"ddd": 4
}
var a = new abc();
console.log(a.constructor);//abc函数
console.log(abc.prototype.constructor);//abc函数
通过对象字面来重写原型对象,该原型对象将不起作用。
function abc() {
this.aaa = 1;
}
abc.prototype.bbb = 2;
abc.prototype = {
constructor: abc,
"ccc": 3,
"ddd": 4
}
var a = new abc();
abc.prototype.eee = 5;//创建实例后不是重写,相当于为重写后的原型对象添加新的属性与方法
console.log(a.aaa);//1
console.log(a.bbb);//undefined
console.log(a.ccc);//3
console.log(a.ddd);//4
console.log(a.eee);//5
function abc() {
this.aaa = 1;
}
abc.prototype.bbb = 2;
var a = new abc();
abc.prototype.ccc = 3;//创建实例后不是重写,相当于为原来的原型对象添加新的属性与方法
console.log(a.aaa);//1
console.log(a.bbb);//2
console.log(a.ccc);//3
function abc() {
this.aaa = 1;
}
abc.prototype.bbb = 2;
var a = new abc();
abc.prototype = {//创建实例后重写原型,不起作用
constructor: abc,
"ccc": 3,
"ddd": 4
}
abc.prototype.eee = 5;
console.log(a.aaa);//1
console.log(a.bbb);//2
console.log(a.ccc);//undefined
console.log(a.ddd);//undefined
console.log(a.eee);//undefined
function Person() {}
Person.prototype = {
constructor: Person,
arrs: [1, 2]
}
var person1 = new Person();
person1.arrs.push(3);
var person2 = new Person();
console.log(person2.arrs);//[1, 2, 3]
原型对象共享的本质使新创建的person2获取的属性发放所person1影响。
一、组合使用构造函数模式和原型模式
使用最广的模式,结合了构造函数与原型的优缺点。不过多复述。
二、动态原型模式
独立的构造函数和原型,动态原型模式将他们分装在一个构造函数中。
三、寄生构造函数模式
为某一个对象添加额外的方法
四、稳妥构造函数模式
定义私有的变量和属性,只能通过函数内部的方法去获取。
function SuperType(name) {
this.name = name;
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this, name);//继承构造函数内部的属性与方法
this.age = age;
}
SubType.prototype = new SuperType();//创建一个SuperType的实例,将其指向SubType的原型对象
SubType.prototype.constructor = SuperType;
SubType.prototype.sayAge = function() {
console.log(this.age);
}
var pcd = new SubType('pcd', 21);
pcd.sayName();
pcd.sayAge();
注1:新创建的SuperType实例指向SubType的原型对象,其中也包括了SuperType内部的属性与方法,但还是将SuperType的属性与方法继承到SubType中是因为原型对象中方法和属性具有共享性。
注2:SubType的原型不能写成字面量的形式,否则会将继承的原型对象覆盖。
function SuperType(name) {
this.name = name;
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this, name);//继承构造函数内部的属性与方法
this.age = age;
}
SubType.prototype = SuperType.prototype;
SubType.prototype.constructor = SuperType;
SubType.prototype.sayAge = function() {
console.log(this.age);
}
var pcd = new SubType('pcd', 21);
pcd.sayName();
pcd.sayAge();
SuperType的原型对象直接赋值给SubType从而实现继承。
function SuperType(name) {
this.name = name;
}
function SubType() {
}
SubType.prototype = SuperType.prototype;
SubType.prototype.constructor = SuperType;
SubType.prototype.sayName = function() {
console.log(this.name);
}
var pcd = new SuperType('pcd');
pcd.sayName();//"pcd"
继承中的父类可以使用子类的原型方法
对于前端开发人员来说,ES6一直早有耳闻,但由于运用不到实际而一直没有安排时间去学习,只是对其有一些粗略的了解。近期在实际开发项目中使用了gulp+webpack对vuejs进行编译,对于vuejs的操作是可以支持ES6的,因为可以使用webpack中的babel-loader进行解析。这节主要讲解对ES6的环境进行搭建,在学习的时候可以进行调试。
通过webpack搭建了一个ES6的环境,在webpack.config.js中定义入口文件问main.js,通过babel对main.js中的ES6的语法进行解析,将其转化为ES5的语法,生成文件为bundle.js。通过index.html引入bundle.js文件进行调试。
module.exports = {
entry: './main',//入口文件
output: {
filename: 'bundle.js'//输出文件
},
module: {
loaders: [{
test: /\.js$/,//正则匹配文件,对其进行解析
exclude: /node_modules/,//不对node_modules里的js文件进行解析
loader: 'babel',//使用babel加载器
query: {
presets: ['es2015']//解析成ES5的形式
}
}]
}
}
<!DOCTYPE html>
<html>
<head>
<title>ES6</title>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
{
"name": "ES6_environment",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {//可以使用npm run的快捷方式
"start": "live-server --port=3004",
"watch": "webpack -w"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.3.17",
"babel-loader": "^6.2.0",
"babel-preset-es2015": "^6.3.13",
"live-server": "^0.9.0",
"webpack": "^1.12.9"
}
}
$ npm install //安装依赖
$ npm run watch //用于监听文件是否发生变化
$ npm start //打开浏览器监听port:3004
以上方法是将ES6的语法编译成ES5后执行,在调试的时候有时不是能很好的体现ES6的属性。也可以通过google浏览器F12在console中直接输入代码编译调试。
参数一为放大值,参数二为缩小值,参数三为基准值
<ul class="flex">
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
.flex{display:flex;width:800px;margin:0;padding:0;list-style:none;}
.flex :nth-child(1){flex:1 1 300px;}
.flex :nth-child(2){flex:2 2 200px;}
.flex :nth-child(3){flex:3 3 400px;}
三个基准值相加为900px大于800px,故需要使用缩小值进行缩小
a: 300 - (1300/(1300 + 2200 + 3400))100) = 284px;
b: 200 - (2200/(1300 + 2200 + 3400))100) = 179px;
c: 400 - (3400/(1300 + 2200 + 3400))*100) = 337px;
<ul class="flex">
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
.flex{display:flex;width:1500px;margin:0;padding:0;list-style:none;}
.flex :nth-child(1){flex:1 1 300px;}
.flex :nth-child(2){flex:2 2 200px;}
.flex :nth-child(3){flex:3 3 400px;}
三个基准值相加为900px小于1500px,故需要使用放大值进行放大
a: 300 + 600 * 1/6 = 400px;
b: 200 + 600 * 2/6 = 400px;
c: 400 + 600 * 3/6 = 700px;
<ul class="flex">
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
.flex{display:flex;width:600px;margin:0;padding:0;list-style:none;}
.flex li:nth-child(1){width:200px;}
.flex li:nth-child(2){flex-grow:1;width:50px;}
.flex li:nth-child(3){flex-grow:3;width:50px;}
300px小于600px,故使用flex-grow放大
a:200px;
b:50 + (600 - 300) * 1 / 4 = 125px;
c:50 + (600 - 300) * 3 / 4 = 275px;
<ul class="flex">
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
.flex{display:flex;width:400px;margin:0;padding:0;list-style:none;}
.flex li{width:200px;}
.flex li:nth-child(3){flex-shrink:3;}
400px小于600px,故使用flex-shrink缩小
a:200 - (1200 / (1200 + 1200 + 3200)) * 200 = 160px
b:200 - (1200 / (1200 + 1200 + 3200)) * 200 = 160px
c:200 - (3200 / (1200 + 1200 + 3200)) * 200 = 80px
参数一:定义弹性盒子元素的排列方向。
参数二:控制flex容器是单行或者多行。
弹性盒子元素的排列方向(该方向为主轴)
属性 | 描述 |
---|---|
row | 主轴为水平方向,起点在左端(默认) |
row-reverse | 主轴为水平方向,起点在右端 |
column | 主轴为垂直方向,起点在上沿 |
column-reverse | 主轴为垂直方向,起点在下沿 |
控制flex容器主轴是单行或者多行。
属性 | 描述 |
---|---|
nowrap | 不换行(默认)如果子元素宽度超出或小于父元素宽度,会通过flex-grow、flex-shrink进行扩大缩小 |
wrap | 换行,第一行在上方 |
wrap-reverse | 换行,第一行在下方 |
定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。可通过flex-wrap: wrap换行设置多跟轴线
属性 | 描述 |
---|---|
flex-start | 与交叉轴的起点对齐。 |
flex-end | 与交叉轴的终点对齐。 |
center | 与交叉轴的中点对齐。 |
space-between | 与交叉轴两端对齐,轴线之间的间隔平均分布。 |
space-around | 每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。 |
stretch(默认值) | 轴线占满整个交叉轴。 |
设置弹性盒子在侧轴方向上的对齐方式
属性 | 描述 |
---|---|
flex-start | 与侧轴的起点对齐。 |
flex-end | 与侧轴的终点对齐。 |
center | 与侧轴的中点对齐。 |
space-between | 与侧轴两端对齐,轴线之间的间隔平均分布。 |
baseline | 第一行文字的基线对齐 |
stretch(默认值) | 轴线占满整个侧轴。 |
设置弹性盒子在主轴上的对齐方式
属性 | 描述 |
---|---|
flex-start | 左对齐(默认) |
flex-end | 右对齐 |
center | 居中 |
space-between | 两端对齐,项目之间的间隔都相等。 |
space-around | 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。 |
设置弹性盒子子元素在侧轴方向上的对齐方式
该属性作用在子元素上,可覆盖align-items
属性 | 描述 |
---|---|
flex-start | 与侧轴的起点对齐。 |
flex-end | 与侧轴的终点对齐。 |
center | 与侧轴的中点对齐。 |
space-between | 与侧轴两端对齐,轴线之间的间隔平均分布。 |
baseline | 第一行文字的基线对齐 |
stretch(默认值) | 轴线占满整个侧轴。 |
设置弹性盒子子元素的排列顺序。数值越小,排列越靠前,默认为0
http协议是无状态的,但用户浏览不同的页面时,服务器是如何判断用户是否是登录的呢?后端通过setcookie将用户的登录session信息编码后传递给浏览器,浏览器每次访问时携带该信息解码后得到session信息从而判断是否处于登录状态。后端设置max-age限制cookie过期时间,设置http-only禁止cookie被JS访问,避免XSS攻击。
使用cookie记录用户的状态时,具体分为以下几个步骤
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', function(req, res, next) {
if (req.cookies.isVisit) {
console.log(req.cookies);
res.send("再次欢迎访问");
} else {
res.cookie('isVisit', 1, {maxAge: 60 * 1000});
res.send("欢迎第一次访问");
}
});
module.exports = app;
当你浏览一个网页时,服务端随机产生一个 1024 比特长的字符串,然后存在你 cookie 中的 connect.sid 字段中。当你下次访问时,cookie 会带有这个字符串,然后浏览器就知道你是上次访问过的某某某,然后从服务器的存储中取出上次记录在你身上的数据
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: 'test',
cookie: { maxAge: 60 * 1000 }
}));
app.get('/', function (req, res) {
if(req.session.isVisit) {
req.session.isVisit++;
res.send('<p>第 ' + req.session.isVisit + '次来此页面</p>');
} else {
req.session.isVisit = 1;
res.send("欢迎第一次来这里");
console.log(req.session);
}
});
module.exports = app;
本文记录了一些node.js中的events模块的学习笔记,基于最新的文档v6.9.1.
var EventEmitter = require('events');
//继承方式一
class MyEmitter extends EventEmitter {};
//继承方式二
var util = require('util');
var MyEmitter = function() {
}
util.inherits(MyEmitter, EventEmitter);
var myEmitter = new MyEmitter();
myEmitter.on('event1', function(arg1, arg2) {
console.log(arg1 + "------" + arg2);
})
myEmitter.emit('event1', 'arg1', 'arg2');
var EventEmitter = require('events');
var util = require('util');
var MyEmitter = function() {
}
util.inherits(MyEmitter, EventEmitter);
var myEmitter = new MyEmitter();
myEmitter.once('eventOnce', function() {
console.log("one");
})
myEmitter.emit('eventOnce');//one
myEmitter.emit('eventOnce');//无输出
var EventEmitter = require('events');
var util = require('util');
var MyEmitter = function() {
}
util.inherits(MyEmitter, EventEmitter);
var myEmitter = new MyEmitter();
var listenFunc = function() {
console.log('remove');
}
myEmitter.on('eventRemove', listenFunc)
myEmitter.emit('eventRemove');//remove
myEmitter.removeListener('eventRemove', listenFunc);
myEmitter.emit('eventRemove');//无输出
通过
Object.getOwnPropertyNames(Object).sort().forEach(function (val) {console.log(val, '\n')});
获取对象的所有自身属性。
function foo() {
console.log(arguments);
}
foo(1, 2, 3, 4);//[1, 2, 3, 4]
console.log(Object.assign({"a": 1, "b": 2}, {"b": 3, "c": 4}));//{a: 1, b: 3, c: 4}
严格模式下不可用,不深入了解
Object.create() 方法创建一个拥有指定原型和若干个指定属性的对象。
// 创建一个原型为null的空对象
var obj1 = Object.create(null);
// 创建一个原型属性a为1的对象
var obj2 = Object.create({a: "1"});
console.log(obj2.a);//1
// 创建一个以另一个空对象为原型,且拥有一个属性p的对象,该属性不可更改
var obj3 = Object.create({}, { p: { value: 42 } });
console.log(obj3.p);//42
// 多用于继承
function Parent(name) {
this.name = name;
}
Parent.prototype.show = function() {
console.log(this.name)
}
function Child(name) {
Parent.call(this, name);
}
Child.prototype = Object.create(Parent.prototype);
var test = new Child('pcd');
test.show();//pcd
多用于数据劫持,监听多个属性
具体实例:MVVM
var obj = {key1: 11, key2: 22}
function observer(obj, key1, key2) {
var old1 = obj.key1;
var old2 = obj.key2;
Object.defineProperties(obj, {
key1: {
enumerable: true,
configurable: true,
get: function() {
return old1;
},
set: function(now) {
if(now !== old1) {
console.log(now);
}
old1 = now
}
},
key2: {
enumerable: true,
configurable: true,
get: function() {
return old2;
},
set: function(now) {
if(now !== old2) {
console.log(now);
}
old2 = now
}
}
})
}
observer(obj, "key1", "key2");
obj.key1 = 2;//2
obj.key2 = 2;//2
多用于数据劫持,监听单个属性
具体实例:MVVM
var obj = {key: 11}
function observer(obj, key) {
var old = obj.key;
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function() {
return old
},
set: function(now) {
if(now !== old) {
console.log(now);
}
old = now
}
})
}
observer(obj, "key");
obj.key = 2;//2
返回一个包含由给定对象所有可枚举属性的属性名和属性值组成的 [属性名,属性值] 键值对的数组
只对最外层进行处理
var obj = { foo: "bar", baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
var obj = { foo: "bar", baz: 42, test: { bb: 1, cc: 2 } };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42], ['test', {bb: 1, cc: 2}] ]
freeze:冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的
isFrozen:判断一个对象是否被冻结
var obj = {
name: "pcd1",
age: 22
}
console.log(obj.name);//pcd1
obj.name = "pcd2";
console.log(obj.name);//pcd2
console.log(Object.isFrozen(obj));//false
Object.freeze(obj);
console.log(Object.isFrozen(obj));//true
obj.name = "pcd3";//报错
用来获取一个对象的一个自身属性的描述符
var obj = {key: 11}
function observer(obj, key) {
var old = obj.key;
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function() {
return old
},
set: function(now) {
if(now !== old) {
console.log(now);
}
old = now
}
})
}
observer(obj, "key");
console.log(Object.getOwnPropertyDescriptor(obj, "key"));
用来获取一个对象的所有自身属性的描述符
var obj = {key1: 11, key2: 22}
function observer(obj, key1, key2) {
var old1 = obj.key1;
var old2 = obj.key2;
Object.defineProperties(obj, {
key1: {
enumerable: true,
configurable: true,
get: function() {
return old1;
},
set: function(now) {
if(now !== old1) {
console.log(now);
}
old1 = now
}
},
key2: {
enumerable: true,
configurable: true,
get: function() {
return old2;
},
set: function(now) {
if(now !== old2) {
console.log(now);
}
old2 = now
}
}
})
}
observer(obj, "key1", "key2");
console.log(Object.getOwnPropertyDescriptors(obj));
返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性)组成的数组
Object.getOwnPropertyNames(Object).sort().forEach(function (val) {console.log(val, '\n')});
//获取Object的所有自身属性
function abc() {
this.name = "pcd";
}
abc.prototype.sex = "man";
var person = {};
person.__proto__ = abc.prototype;
//Object.setPrototypeOf(person, abc.prototype);
abc.call(person);
console.log(person.name);//pcd
console.log(person.sex);//man
console.log(Object.getPrototypeOf(person));//abc.prototype
isExtensible() 决定一个对象是否可扩展 (即是否能够添加新的属性)
preventExtensions 用來避免物件被新增新的属性
preventExtensions
var empty = {};
console.log(Reflect.isExtensible(empty));//true
Reflect.preventExtensions(empty);
console.log(Reflect.isExtensible(empty)); //false
Object.seal() 方法可以让一个对象密封,与冻结freeze的区别是属性可以修改
Object.isSealed: 判断对象是否被密封
var obj = {
name: "pcd1",
age: 22
}
console.log(obj.name);//pcd1
obj.name = "pcd2";
console.log(obj.name);//pcd2
console.log(Object.isSealed(obj));//false
Object.seal(obj);
console.log(Object.isSealed(obj));//true
obj.name = "pcd3";
console.log(obj.name);//pcd3
返回属性及属性值
var arr = ["a", "b", "c"];
console.log(Object.keys(arr));//["0", "1", "2"]
console.log(Object.values(arr));//["a", "b", "c"]
多用于数组,数组也为对象
var arr = ["a", "b", "c"];
console.log(arr.length);//3
方法用来判断两个值是否是同一个值
console.log(-0 === +0);//true
console.log(Object.is(-0, +0));//false
console.log(NaN === NaN);//false
console.log(Object.is(NaN, NaN));//true
详见#35
document.body.addEventListener('click', function() {
console.log('body');
}, false);
document.getElementById('div1').addEventListener('click', function() {
console.log('div1');
}, false);
//div1 body
document.body.addEventListener('click', function() {
console.log('body');
}, true);
document.getElementById('div1').addEventListener('click', function() {
console.log('div1');
}, true);
//body div1
document.body.addEventListener('click', function() {
console.log('body');
}, false);
document.getElementById('div1').addEventListener('click', function() {
console.log('div1');
}, true);
//div1 body
//捕获优先级高
document.body.addEventListener('click', function() {
console.log('body');
}, true);
document.getElementById('div1').addEventListener('click', function() {
console.log('div1');
}, false);
//body div1
//捕获优先级高
IEModel的实现给绑定处理程序设置了错误的上下文,使的处理程序内的this引用的是全局上下文而不是事件目标元素,使用apply、call或bind将事件绑定在目标元素上。
if(document.addEventListener) {
this.addEvent = function(elem, type, fn) {
elem.addEventListener(type, fn, false);
return fn;//返回函数用于解绑
}
this.removeEvent = function(elem, type, fn) {
elem.removeEventListener(type, fn, false);
}
}else if(document.attachEvent) {
this.addEvent = function(elem, type, fn) {
var bound = function() {
return fn.apply(elem, arguments);
}//将this的指向elem
elem.attachEvent('on' + type, bound);
return bound;//返回函数用于解绑
}
this.removeEvent = function(elem, type, fn) {
elem.detachEvent('on' + type, fn);
}
}
本文记录了一些node.js中的multer中间件的学习笔记。以下的例子基于express框架
###单个文件上传
<form enctype="multipart/form-data" method="post">
<input type="file" name="uploadInput" />
<input id='submitFile' type="submit" />
</form>
router.get('/uploadSingle', function(req, res, next) {
res.render('uploadSingle', {});
});
router.post('/uploadSingle', function(req, res, next) {
var upload = muilter.single('uploadInput');
upload(req, res, function(err) {
console.log(req.file);
})
})
<form enctype="multipart/form-data" method="post">
<input type="file" name="uploadInput" />
<input type="file" name="uploadInput" />
<input type="file" name="uploadInput" />
<input id='submitFile' type="submit" />
</form>
router.get('/uploadArray', function(req, res, next) {
res.render('uploadArray', {});
});
router.post('/uploadArray', function(req, res, next) {
var upload = muilter.array('uploadInput', 3);
upload(req, res, function(err) {
console.log(req.files);
})
})
<form enctype="multipart/form-data" method="post">
<input type="file" name="uploadInput" />
<input type="file" name="uploadInput" />
<input type="file" name="uploadInput1" />
<input type="file" name="uploadInput1" />
<input type="file" name="uploadInput2" />
<input type="file" name="uploadInput2" />
<input type="file" name="uploadInput2" />
<input id='submitFile' type="submit" />
</form>
router.get('/uploadFilter', function(req, res, next) {
res.render('uploadFilter', {});
});
router.post('/uploadFilter', function(req, res, next) {
var upload = muilter.fields([{ name: 'uploadInput', maxCount: 2 }, { name: 'uploadInput1', maxCount: 2 }, { name: 'uploadInput2', maxCount: 4 }])
upload(req, res, function(err) {
if(err) {
console.log(err);
}
console.log(req.files);
})
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>浮动</title>
<style type="text/css">
*{
padding: 0;
margin: 0;
}
#main {
background-color: green;
}
#div1 {
background: yellow;
width: 200px;
height: 200px;
float: left;
}
#div2 {
background-color: blue;
width: 200px;
height: 200px;
float: left;
}
</style>
</head>
<body>
<div id="main">
<div id="div1">
</div>
<div id="div2">
</div>
</div>
</body>
</html>
此时父元素#main的高度宽度由子元素#div1与#div2决定,由于子元素设置浮动脱离文档流,导致父元素高度为0,使其父元素#main背景颜色无效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>浮动</title>
<style type="text/css">
*{
padding: 0;
margin: 0;
}
#main {
background-color: green;
overflow: hidden;
}
#div1 {
background: yellow;
width: 200px;
height: 200px;
float: left;
}
#div2 {
background-color: blue;
width: 200px;
height: 200px;
float: left;
}
</style>
</head>
<body>
<div id="main">
<div id="div1">
</div>
<div id="div2">
</div>
</div>
</body>
</html>
父元素设置overflow: hidden;属性
原理:因为overflow.hidden会触发BFC(块级排版上下文)。都会为他们的内容创建新的块级格式化上下文
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>浮动</title>
<style type="text/css">
*{
padding: 0;
margin: 0;
}
#main {
background-color: green;
}
#div1 {
background: yellow;
width: 200px;
height: 200px;
float: left;
}
#div2 {
background-color: blue;
width: 200px;
height: 200px;
float: left;
}
.clear{
clear:both;
height: 0;
line-height: 0;
font-size: 0
}
</style>
</head>
<body>
<div id="main">
<div id="div1">
</div>
<div id="div2">
</div>
<div class="clear">
</div>
</div>
</body>
</html>
添加一个子元素div,设置clear: both;属性
缺点:每次清除浮动都需要添加一个子元素div
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>浮动</title>
<style type="text/css">
*{
padding: 0;
margin: 0;
}
#main {
background-color: green;
}
#div1 {
background: yellow;
width: 200px;
height: 200px;
float: left;
}
#div2 {
background-color: blue;
width: 200px;
height: 200px;
float: left;
}
.clear:after {
content:".";
display:block;
height:0;
visibility:hidden;
clear:both;
}
</style>
</head>
<body>
<div id="main" class="clear">
<div id="div1">
</div>
<div id="div2">
</div>
</div>
</body>
</html>
使用after伪类,则不需要每次清除浮动都新建一个子元素
作为新一代的青年,当当会用sourcetree怎么能行,上git指令。今后工作中会使用git指令修改代码,会不断进行修改与补充。
本文主要介绍DOM的元素、文本与属性三个节点
nodeName:节点名字
nodeValue:节点的值
nodeType:节点的类型常数值
DOM的原子是元素节点
<div id="div1" title="div2">div3</div>
console.log(document.getElementById('div1').nodeName);//DIV
console.log(document.getElementById('div1').nodeValue);//null
console.log(document.getElementById('div1').nodeType);//1
<div id="div1" title="div2">div3</div>
console.log(document.getElementById('div1').childNodes[0].nodeName);//#text
console.log(document.getElementById('div1').childNodes[0].nodeValue);//div3
console.log(document.getElementById('div1').childNodes[0].nodeType);//3
<div id="div1" title="div2">div3</div>
console.log(document.getElementById('div1').getAttributeNode('title').nodeName);//title
console.log(document.getElementById('div1').getAttributeNode('title').nodeValue);//div2
console.log(document.getElementById('div1').getAttributeNode('title').nodeType);//2
返回元素节点 | 返回所有节点 |
---|---|
children | childNodes |
childElementCount | childNodes.length |
firstElementChild | firstChild |
lastElementChild | lastChild |
nextElementSibling | nextSibling |
previousElementSibling | previousSibling |
var fragment = document.createDocumentFragement();
//添加节点到fragment
//...
document.body.appendChild(fragment);
querySelector()用来获取第一个匹配的节点
querySelectorAll()用来获取全部匹配到的节点
<div id="main" class="foo"></div>
var oDiv = document.getElementById('main');
console.log(oDiv.classList);//["foo"]
oDiv.classList.add('bar');
console.log(oDiv.classList);//["foo", "bar"]
console.log(oDiv.classList.item(0));//foo
console.log(oDiv.classList.item(1));//bar
console.log(oDiv.classList.item(2));//null
oDiv.classList.remove('foo');
console.log(oDiv.classList);//["bar"]
oDiv.classList.toggle('foo');
console.log(oDiv.classList);//["bar", "foo"]
oDiv.classList.toggle('foo');
console.log(oDiv.classList);//["bar"]
console.log(oDiv.classList.contains("bar"));//true
console.log(oDiv.classList.contains("foo"));//false
<div id="main" class="foo"></div>
var oDiv = document.getElementById('main');
console.log(oDiv.classList);//["foo"]
oDiv.classList.add('bar');
console.log(oDiv.classList);//["foo", "bar"]
console.log(oDiv.classList.item(0));//foo
console.log(oDiv.classList.item(1));//bar
console.log(oDiv.classList.item(2));//null
oDiv.classList.remove('foo');
console.log(oDiv.classList);//["bar"]
oDiv.classList.toggle('foo');
console.log(oDiv.classList);//["bar", "foo"]
oDiv.classList.toggle('foo');
console.log(oDiv.classList);//["bar"]
console.log(oDiv.classList.contains("bar"));//true
console.log(oDiv.classList.contains("foo"));//false
本文跨域处理后台以PHP为例,首先下载wamp,我们先在本地配置俩个域名:pcd.me(一级域名)与dev.pcd.me(二级域名)。在www目录下新建pcd和dev俩个文件,当访问pcd.me时则访问pcd文件夹下的文件,访问dev.pcd.me则访问dev文件夹下的文件。
更改C:\Windows\System32\drivers\etc\host文件:添加
127.0.0.1 pcd.me
127.0.0.1 dev.pcd.me
更改F:\wamp2\wamp\bin\apache\apache2.4.23\conf\extra\httpd-vhosts.conf(该目录为我的配置,具体以实际为准)
<VirtualHost *:80>
ServerName pcd.me
DocumentRoot F:/wamp2/wamp/www/pcd
<Directory "F:/wamp2/wamp/www/pcd/">
Options +Indexes +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require local
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName dev.pcd.me
DocumentRoot F:/wamp2/wamp/www/dev
<Directory "F:/wamp2/wamp/www/dev/">
Options +Indexes +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require local
</Directory>
</VirtualHost>
在pcd文件下新建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
main
</body>
</html>
在dev文件下新建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
dev
</body>
</html>
此时访问pcd.me页面显示main,访问dev.pcd.me页面显示dev。
在pcd文件下ajax.php
<?php
echo 1;
?>
在pcd.me发起异步请求即
pcd文件下的index文件更改为
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="//cdn.bootcss.com/jquery/3.1.1/jquery.js"></script>
</head>
<body>
dev
<script type="text/javascript">
$.ajax({
type: "GET",
url: "http://pcd.me/ajax.php"
success: function(data) {
console.log(data);//11
}
})
</script>
</body>
</html>
在dev.pcd.me发起异步请求即
dev文件下的index文件更改为
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="//cdn.bootcss.com/jquery/3.1.1/jquery.js"></script>
</head>
<body>
dev
<script type="text/javascript">
$.ajax({
type: "GET",
url: "http://pcd.me/ajax.php"
success: function(data) {
console.log(data);//报错
//XMLHttpRequest cannot load http://pcd.me/ajax.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://dev.pcd.me' is therefore not allowed access.
}
})
</script>
</body>
</html>
当dev.pcd.me页面向pcd.me发起异步请求时则为跨域处理。至此环境搭建成功。
浏览器厂商针对Web客户端制定实现重要的安全概念:同源策略(SOP)。它的核心是确保不同源提供的文件之间是相互独立的,只有当不同的脚本文件是有相同的域、端口、HTTP协议提供时,才没有特殊限制访问对方的DOM方法和属性。当一个脚本访问不同源的文档中的方法和属性使,便会抛出异常错误。
当我们需要访问不同源的文件时,要么绕开同源策略(JSNP与子域代理),要么使用跨域资源共享(CORS)的“正式”技术。
同源策略有个例外: HTML脚本是可以规避SOP检查的。JSONP利用这个例外实现跨域数据加载。
<script type="text/javascript" src="http://pcd.me/ajax.php"></script>
dev.pcd.me页面通过以上方式发起请求时,避开SOP,实现跨域请求,但对于返回的数据无法解析。
于是需要我们改写返回的数据形式
<?php
$number = 11;
echo 'abc('.$number.')';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="//cdn.bootcss.com/jquery/3.1.1/jquery.js"></script>
</head>
<body>
dev
<script type="text/javascript">
Window.abc = function(number) {
console.log(number);//11
}
</script>
<script type="text/javascript" src="http://pcd.me/ajax.php"></script>
</body>
</html>
客户端通过定义一个函数,异步回调执行该函数,则函数中的参数为数据。
window.jsonpCallback = function(json) {
console.log(json)
}
var script = document.createElement('script');
script.async = true;
script.src = "http://pcd.me/ajax.php?callback=jsonpCallback";
document.body.appendChild(script);
<?php
header('Content-type: application/javascript');
$callback = $_GET['callback'];
$person = json_encode(array(
'name' => 'pcd',
'age' => '21',
'sex' => 'man'
), JSON_PRETTY_PRINT);
echo "$callback($person)";
?>
1.JSONP仅适用于HTTP的GET请求,譬如图片、文字等无法实现上传
2.JSONP返回调用回调函数,如何没有调用成功,则无任何提示,只能是给定一个时间,没有收到响应则为请求失败
浏览器根据SOP认为dev.pcd.me与pcd.me是不同的源,但浏览器允许网站将主机部分更改为原始值的后缀,即寄放在dev.pcd.me的页面可以将他的源设置为pcd.me,但不能修改源的端口号与HTTP协议。
<?php
echo 11;
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子页面</title>
<script type="text/javascript">document.domain = 'pcd.me'</script>
<script type="text/javascript" src="jquery-1.11.2.min.js"></script>
</head>
<body>
<div>dev</div>
<script type="text/javascript">
function getProducData() {
var iframe = document.createElement('iframe');
iframe.src = 'http://pcd.me/proxy.html';
iframe.onload = function() {
iframe.contentWindow.jQuery.ajax({//这里使用jquery的ajax方式调用则需要在proxy.html中引入jquery
method: "GET",
url: "http://pcd.me/ajax.php",
success: function(data) {
console.log(data);
}
})
}
document.getElementsByTagName('head')[0].appendChild(iframe);
}
getProducData();
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<script>
document.domain = 'pcd.me';
</script>
<script type="text/javascript" src="//cdn.bootcss.com/jquery/3.1.1/jquery.js"></script>
</html>
1.只适用于子域名下,运用范围窄
2.需要添加一个代理文件
<?php
echo '<!DOCTYPE>
<html>
<script>
document.domain = "pcd.me";
window.parent.jsonpCallback("{\"status\": \"success\"}");
</script>
</html>
';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子页面</title>
<script type="text/javascript">document.domain = 'pcd.me'</script>
<script type="text/javascript" src="jquery-1.11.2.min.js"></script>
</head>
<body>
<div>dev</div>
<script type="text/javascript">
function jsonpCallback(value) {
console.log(value);
}
</script>
<script type="text/javascript">
var frame = document.createElement('iframe');
frame.name = "post-review";
frame.style.display = "none";
var form = document.createElement("form");
form.action = "http://pcd.me/ajax.php";
form.method = "GET";
form.target = "post-review";
document.body.appendChild(form);
document.body.appendChild(frame);
form.submit();
document.body.removeChild(form);
</script>
</body>
</html>
1.JSONP仅适用于HTTP的GET请求,譬如图片、文字等无法实现上传
2.JSONP返回调用回调函数,如何没有调用成功,则无任何提示,只能是给定一个时间,没有收到响应则为请求失败
3.相较于JSONP,其能实现POST请求
当发起http请求时,支持CORS的浏览器会通过引入额外的Origin头信息来指定请求源。
Origin: http://de.pcd.me
服务端的工作是检查头信息是否接受该请求,如果一个请求被接受,他必须发挥一个包含Access-Control-Allow-Origin: http://dev.pcd.me
<?php
header('Access-Control-Allow-Origin: http://dev.pcd.me');
echo 11;
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子页面</title>
<script type="text/javascript" src="jquery-1.11.2.min.js"></script>
</head>
<body>
<div>dev</div>
<script type="text/javascript">
$.ajax({
type: "GET",
url: "http://pcd.me/ajax.php",
success: function(data) {
console.log(data);
}
})
</script>
</body>
</html>
dev目录下index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Cross-domain communication using HTML5</title>
<script type="text/JavaScript">
function sendIt(){
// 通过 postMessage 向子窗口发送数据
document.getElementById("otherPage").contentWindow
.postMessage(
document.getElementById("message").value,
"http://pcd.me"
);
}
</script>
</head>
<body>
<!-- 通过 iframe 嵌入子页面 -->
<iframe src="//pcd.me/other-domain.html"
id="otherPage"></iframe>
<br/><br/>
<input type="text" id="message"><input type="button"
value="Send to child.com" onclick="sendIt()" />
</body>
</html>
pcd目录下other-domain.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Web page from dev.pcd.me</title>
<script type="text/JavaScript">
//event 参数中有 data 属性,就是父窗口发送过来的数据
window.addEventListener("message", function( event ) {
// 把父窗口发送过来的数据显示在子窗口中
document.getElementById("content").innerHTML+=event.data+"<br/>";
}, false );
</script>
</head>
<body>
Web page from http://dev.pcd.me
<div id="content"></div>
</body>
</html>
关于页面布局之前找了很多案例,当时是看懂了,但当让你写的时候发现自己视乎并不清楚他的原理,于是决定花些时间去整理一下关于页面布局的资料。主要分为俩列自适应布局,三列自适应布局,等高布局。
* {
padding: 0;
margin: 0;
}
#main {
height: 800px;
background-color: yellow;
}
#left {
float: left;
width: 220px;
height: 500px;
background-color: red;
}
#right {
padding-left: 220px;/* margin-left: 220px;border-left: 220px solid; */
background-color: green;
height: 500px;
}
<div id="main">
<div id="left"></div>
<div id="right"></div>
</div>
原理:
在元素不设宽度的情况下:
若元素为普通流中元素,元素宽度等于父元素宽度;
若元素不在文档流中,元素宽度等于内容宽度;
* {
padding: 0;
margin: 0;
}
#main {
height: 800px;
background-color: yellow;
}
#left {
float: left;
width: 220px;
height: 500px;
background-color: red;
}
#right {
width: 100%;
padding-left: 220px;
box-sizing: border-box;
/* border-left: 220px solid;
box-sizing: border-box; */
background-color: green;
height: 500px;
}
<div id="main">
<div id="left"></div>
<div id="right"></div>
</div>
原理:
在元素宽度为100%的情况下:
若元素为普通流元素或者浮动元素,元素宽度为父元素宽度的100%;若元素为绝对定位元素,元素宽度为元素offset-parent宽度的100%;若元素为固定定位元素,元素宽度始终为body的100%
设置box-sizing(兼容性IE8+)使#right的宽度为原来的100%。
* {
padding: 0;
margin: 0;
}
#main {
height: 800px;
background-color: yellow;
overflow: hidden;
width: 100%;
}
#left {
float: left;
width: 200px;
background-color: red;
height: 300px;
margin-right: -200px;
}
#right {
float: left;
width: 100%;
height: 300px;
border: 1px solid;
}
#rightContent {
margin-left: 200px;
height: 300px;
background-color: white;
}
<div id="main">
<div id="left"></div>
<div id="right">
<div id="rightContent">
</div>
</div>
</div>
原理:
1.首先将#left设置固定宽度并向左浮动,#right设置width: 100%; 并向左浮动。由于页面宽度限制#left与#right会处于俩行。
2.将#left设置css属性margin-right: -#left的宽度; 让其不占据原来的位置,此时的#left与#right处于同一行,但#right会覆盖掉#left。
3.设置#rightContent的margin-left: #left的宽度px。
* {
padding: 0;
margin: 0;
}
#main {
width: 100%;
background-color: yellow;
overflow: hidden;
height: 500px;
}
#left {
float: left;
width: 150px;
background-color: red;
height: 300px;
margin-right: -150px;
}
#right {
float: left;
width: 200px;
background-color: green;
height: 300px;
margin-left: -200px;
}
#center {
float: left;
height: 300px;
width: 100%;
}
#centerContent {
height: 300px;
margin: 0 200px 0 150px;
background-color: white;
}
<div id="main">
<div id="left"></div>
<div id="center">
<div id="centerContent">
</div>
</div>
<div id="right"></div>
</div>
原理:
原理跟俩列布局的俩边都浮动的自适应相同
右边的定位使用了marin-left: -#left的宽度值; 原理与#right相同。
该方式简单,不做叙述。该方法不能实现等高布局,在设置定位的时候父元素要有高度,不能实现高度自适应。
* {
padding: 0;
margin: 0;
}
#main {
width: 100%;
background-color: yellow;
overflow: hidden;
position: relative;
height: 500px;
}
#left {
width: 150px;
background-color: red;
height: 300px;
float: left;
margin-right: -150px;
}
#center {
width: 200px;
background-color: green;
height: 300px;
float: left;
position: relative;
left: 150px;
}
#right {
width: 100%;
float: left;
height: 300px;
}
#rightContent {
background-color: white;
margin-left: 350px;
height: 300px;
}
<div id="main">
<div id="left"></div>
<div id="center">
</div>
<div id="right">
<div id="rightContent">
</div>
</div>
</div>
原理:
原理跟俩列布局的俩边都浮动的自适应相同
但中间块#center的布局使用了绝对定位的方式
* {
padding: 0;
margin: 0;
}
#main {
width: 100%;
background-color: yellow;
overflow: hidden;
}
#left {
float: left;
width: 150px;
background-color: red;
padding-bottom: 9999px;
margin-bottom: -9999px;
margin-right: -150px;
}
#right {
float: left;
width: 100%;
padding-bottom: 9999px;
margin-bottom: -9999px;
}
#rightContent {
margin-left: 150px;
background-color: green;
}
<div id="main">
<div id="left">aaaa</div>
<div id="right">
<div id="rightContent">
aaaa<br><br><br>aaaa
</div>
</div>
</div>
原理:
父元素#main不设高度设置overflow: hidden;,#left与#right设置css属性padding-bottom: 9999px; margin-bottom: -9999px;以上示例以俩列布局俩边均浮动为例,其余俩种俩列自适应方式及三列自适应均可实现。
使用定位的布局方式不可实现等高布局,使用定位布局的时候需要先给父级添加一个高度值
Object.is与==与===与if(){}的判断
使用 == 会做类型的转化
conosle.log('1' == 1);//true
前后的类型也要相同
console.log('1' === 1);//false
与===相近,有俩个特殊情况
console.log(-0 === +0);//true
console.log(Object.is(-0, +0));//false
console.log(NaN === NaN);//false
console.log(Object.is(NaN, NaN));//true
如需执行if中的语句,则if中的条件需要为真值,
js里的“真值”很好判断,因为“假值”总共只有6个:
false,undefined,null,0,""(空字符串),NaN
除此之外的所有值,都是“真值”,即在逻辑判断中可以当true来使用
http://dorey.github.io/JavaScript-Equality-Table/
https://www.zhihu.com/question/47555543
http://stackoverflow.com/questions/30543190/object-is-vs
没调用对象指向全局
function foo() {
console.log(this.a);
}
var a = 1;
foo();//1
var a = 1;
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
obj.foo();//2
var bar = obj.foo;
bar();//1
function foo() {
console.log(this.a);
}
var a = 1;
var obj = {
a: 2
}
foo.call(obj);//2
foo.apply(obj);//2
var bar = foo.bind(obj);
bar();//2
function foo(a) {
this.a = a;
}
var a = 1;
var bar = new foo(3);
console.log(bar.a);//3
function foo() {
console.log(this.a);
}
var obj1 = {
a: 1,
foo: foo
}
var obj2 = {
a: 2
}
obj1.foo();//1
obj1.foo.call(obj2);//2
所以显式优先级高于隐式
function foo(a) {
this.a = a;
}
var obj = {
a: 1,
foo: foo
}
obj.foo(2);
console.log(obj.a);//2
var bar = new obj.foo(3);
console.log(obj.a);//2此时obj.foo(3)未起作用,new优先级大于隐式
console.log(bar.a);//3
function foo(a) {
this.a = a;
}
var obj = {};
var bar = foo.bind(obj);
bar(2);
console.log(obj.a);//2
var baz = new bar(3);
console.log(obj.a);//2使用new未将obj.a改变为3,显式优先级高于new
console.log(baz.a);//3this绑定新创建的对象baz
function foo() {
console.log(this.a);
}
var a = 1;
foo.call(null);//1
var Ø = Object.create(null);
function foo() {
console.log(this.a);
}
foo.call(Ø);//undefined
以下例子需要ES6环境下使用,可参考https://github.com/PLDaily/ES6
var Person = function() {
this.name = 'pcd';
this.hello = () => {
console.log(this.name);//this在定义是已经被锁死
}
}
var bb = new Person();
bb.hello.bind({"name": "dcp"});
bb.hello();//pcd
var a;
a++;
console.log(a);//NaN
xhr = new XMLHttpRequest();
http返回的状态码
xhr.withCredentials代表是否携带cookie。
cookies也是一种认证信息,在跨域请求中,client端必须手动设置xhr.withCredentials=true,且server端也必须允许request能携带认证信息(即response header中包含Access-Control-Allow-Credentials:true),这样浏览器才会自动将cookie加在request header中。
var form_data = new FormData();
form_data.append('longitude', _this.nowloc.lng);
form_data.append('latitude', _this.nowloc.lat);
form_data.append('city', _this.nowloc.city);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/point/near', true);
xhr.send(form_data);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200) {
console.log(typeof xhr.responseText);//string
}
};
https://segmentfault.com/a/1190000004322487
http://www.ruanyifeng.com/blog/2012/09/xmlhttprequest_level_2.html
网络由下往上分为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。其中IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用层。
PC/IP协议是传输层协议,主要解决数据如何在网络中传输
TCP/IP协议的封装和应用
HTTP是应用层协议,主要解决如何包装数据。我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容
HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”
在HTTP/1.0中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。如果客户端浏览器访问的某个HTML或其他类型的 Web页中包含有其他的Web资源,如JavaScript文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话。
但从 HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:
UDP不是面向连接的,UDP传送数据前并不与对方建立连接,对接收到的数据也不发送确认信号,发送端不知道数据是否会正确接收,当然也不用重发,所以说UDP是无连接的、不可靠的一种数据传输协议
http://www.cnblogs.com/0201zcr/p/4694945.html
https://www.zhihu.com/question/39541968/answer/81841947
一般情况下在使用对象调用函数是会使用以下方式书写,将对象赋值给函数内部的局部变量,调用函数时能从局部变量中获取
var x = 10;
var myObj = {
x: 0,
deal: function() {
var that = this;
return function() {
return ++that.x;
}
}
};
var aaa = myObj.deal();
console.log(aaa());//1
不将对象赋值到函数内部的局部变量,函数调用时从全局中去获取
var aaa = myObj.deal();
console.log(aaa());//1
var x = 10;
var myObj = {
x: 0,
deal: function() {
return function() {
return ++this.x;
}
}
};
var aaa = myObj.deal();
console.log(aaa());//11
bind相当于将myObj(上下文)传入到函数中
var x = 10;
var myObj = {
x: 0,
deal: function() {
return (function() {
return ++this.x;
}).bind(this);
}
};
var aaa = myObj.deal();
console.log(aaa());//1
bind使用参数的形式传入时
function foo(p1) {
this.val = p1;
}
var baz = foo.bind(null, 'p1');
var bar = new baz('p2');
console.log(bar.val);//p1
function foo(p1, p2) {
this.val = p1 + p2;
}
var baz = foo.bind(null, 'p1');
var bar = new baz('p2');
console.log(bar.val);//p1p2
function foo(p1) {
this.val = p1;
}
var baz = foo.bind('p1');
var bar = new baz('p2');
console.log(bar.val);//p2
使用new新建对象时即被忽略
Math.floor(Math.random() * 98 + 3 + 1) - 1;
Math.random() 获取到的数值为[0, 1)
Math.random() * 98 获取到的值为[0, 98)
Math.random() * 98 + 3 获取到的值为[3, 101)
Math.random() * 98 + 3 + 1 获取到的值为[4, 102)
Math.floor(Math.random() * 98 + 3 + 1) 获取到的值为[4, 101]中的整数
Math.floor(Math.random() * 98 + 3 + 1) - 1; 获取到值为为[3, 100]中的整数
加班近一个星期,回学校写一个星期的论文,又俩个星期没有更新博客了。最近新入手一台mac,记录一下搭建php环境的过程。mac自带apache与php,但由于mac系统更新时会更新apache与PHP,导致php环境需要重新配置,故选择使用xampp。
sudo /Applications/XAMPP/xamppfiles/bin/mysql.server start
sudo killall mysqld
manager-osx > start mysql
LoadModule vhost_alias_module modules/mod_vhost_alias.so
Include etc/extra/httpd-vhosts.conf
<VirtualHost *:80>
ServerAdmin [email protected]
DocumentRoot "/Applications/XAMPP/xamppfiles/htdocs/laravel/public"
ServerName www.shop123.com
ErrorLog "logs/dummy-host2.example.com-error_log"
CustomLog "logs/dummy-host2.example.com-access_log" common
<Directory "/Applications/XAMPP/xamppfiles/htdocs/laravel/public">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
<IfModule unixd_module>
#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# It is usually good practice to create a dedicated user and group for
# running httpd, as with most system services.
#
User pengchangdong
Group daemon
</IfModule>
以一个简单的例子为例,我们要实现一个链式的调用,例:
Man('pcd').eat('lunch').eat('dinner')
该方法简单,只需我们新建一个对象,将Man、eat作为对象的属性,每次调用时返回该对象变可以实现
例:
function _Man(name) {
console.log('I am ' + name);
}
_Man.prototype.eat = function(something) {
console.log('eat ' + something);
return this;
}
function Man(name) {
return new _Man(name);
}
Man('pcd').eat('lunch').eat('dinner');
//I am pcd
//eat lunch
//eat dinner
此时我们想改变一下,pcd不想吃完中饭后直接去吃晚饭,他想过5s之后再去吃晚饭
Man('pcd').eat('lunch').wait(5000).eat('dinner');
改变上面的例子
function _Man(name) {
console.log('I am ' + name);
}
_Man.prototype.eat = function(something) {
console.log('eat ' + something);
return this;
}
_Man.prototype.wait = function(time) {
setTimeout(function() {
console.log('wait ' + time);
}, time);
return this;
}
function Man(name) {
return new _Man(name);
}
Man('pcd').eat('lunch').wait(5000).eat('dinner');
//I am pcd
//eat lunch
//eat dinner
//wait 5000
输出的结果跟我们的预期不符,我们需要先"wait 5000"后再"ear dinner";当然你会想我们可以再执行完定时器之后再回到this对象就好了。如下
function _Man(name) {
console.log('I am ' + name);
}
_Man.prototype.eat = function(something) {
console.log('eat ' + something);
return this;
}
_Man.prototype.wait = function(time) {
var _this = this;
setTimeout(function() {
console.log('wait ' + time);
return _this;
}, time);
}
function Man(name) {
return new _Man(name);
}
Man('pcd').eat('lunch').wait(5000).eat('dinner');
//I am pcd
//eat lunch
//Cannot read property 'eat' of undefined
但是却报了eat为undefined,因为我们在执行定时器操作相当于异步操作,而Man('pcd').eat('lunch').wait(5000).eat('dinner');中wait函数后的eat还需要继续执行,但此时的this还没有返回,故找不到eat的方法。所以我们需要换一种方式解决。
首先,我们先执行链式调用的Man('pcd').eat('lunch').wait(5000).eat('dinner');但不实际操作该函数,只是将其存放在数组中,通过setTimeout执行异步操作,从数组中一个个去除执行变可以了,如下:
function _Man(name) {
console.log('I am ' + name);
var _this = this;
this.funcArr = [];
setTimeout(function() {
_this.next();
})
}
_Man.prototype.next = function() {
var fn = this.funcArr.shift();
fn&&fn();
}
_Man.prototype.eat = function(something) {
var _this = this;
var func = function(something) {
console.log('eat ' + something);
_this.next()
}
this.funcArr.push(func);
return this;
}
_Man.prototype.wait = function(time) {
var _this = this;
var func = function(time) {
setTimeout(function() {
console.log('wait ' + time);
_this.next();
}, time);
}
this.funcArr.push(func);
return this;
}
function Man(name) {
return new _Man(name);
}
Man('pcd').eat('lunch').wait(5000).eat('dinner');
//I am pcd
//eat undefined
//wait undefined
//eat undefined
此时你会发现函数虽然放入数组并一个个执行了,但函数的参数并没有传入进去。此时我们便需要使用高大上的闭包存储变量了。
function _Man(name) {
console.log('I am ' + name);
var _this = this;
this.funcArr = [];
setTimeout(function() {
_this.next();
})
}
_Man.prototype.next = function() {
var fn = this.funcArr.shift();
fn&&fn();
}
_Man.prototype.eat = function(something) {
var _this = this;
var func = (function(something) {
return function() {
console.log('eat ' + something);
_this.next();
}
})(something);
this.funcArr.push(func);
return this;
}
_Man.prototype.wait = function(time) {
var _this = this;
var func = (function(time) {
return function() {
setTimeout(function() {
console.log('wait ' + time);
_this.next();
}, time);
}
})(time);
this.funcArr.push(func);
return this;
}
function Man(name) {
return new _Man(name);
}
Man('pcd').eat('lunch').wait(5000).eat('dinner');
//I am pcd
//eat lunch
//wait 5000
//eat dinner
大功告成。。。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.