wencaistorm / gulp-demos Goto Github PK
View Code? Open in Web Editor NEWgulp-demos
gulp-demos
test001
先挖个坑,日后再填
jQuery.extend = jQuery.fn.extend = function() {
/*
* 所有的变量声明都放在最上面,会比较清晰
* arguments: 传入的参数列表,类 Array
* target: 目标对象,其他对象的成员属性将被附加到该对象上,默认值为传入第一个参数
* deep: 表示是否进行深拷贝,默认值为 false
* i: 用来拷贝的对象在参数列表中的索引,默认为 1 (即从第二个参数开始)
*/
var options, name, src, copy, copyIsArray, clone,
target = arguments[ 0 ] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
/*
* 如果传入第一个参数为 boolean 类型,则该参数用来指定是否进行深拷贝
* 那么,目标对象和用来拷贝的对象按参数顺序往后推一个位置
* 即将第二个参数指定为 target,同时 i++
*/
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
/*
* 如果目标对象不是 Object 类型,将目标对象设为空对象
* ??? 为什么要判断是否为一个函数
*/
if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
target = {};
}
// Extend jQuery itself if only one argument is passed
/*
* 如果没有传入用来拷贝的对象,???
*/
if ( i === length ) {
target = this;
i--;
}
/*
* 这里对用来拷贝的对象进行遍历
* i 已经进行初始化,所以只写一个分号
*/
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
/*
* 赋值运算 和 逻辑判断在一条语句中实现
* 传入的参数不能为 null
* ??? undefined 呢?
*/
if ( ( options = arguments[ i ] ) != null ) {
// Extend the base object
/*
* 对参数的属性进行遍历
* src: 目标对象的属性值
* copy: 拷贝对象的属性值
*/
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
/*
* ???
*/
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
/*
* 进行递归运算的三个条件
* 1. 调用时传入的第一个参数为 true
* 2. 拷贝对象的属性值不为 undefined、null
* 3. 拷贝对象的属性值为 Object 或者 Array 类型
*/
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
( copyIsArray = Array.isArray( copy ) ) ) ) {
if ( copyIsArray ) {
/*
* 如果拷贝对象的属性值为 Array 类型,则重置 copyIsArray 为 false,以便下次循环使用
* 同时,如果目标对象的同名属性值 src 存在且同为 Array 类型,将 src 赋值给 clone,作为递归调用时的目标对象
* 否则赋值为空数组
*
* 同理,如果拷贝对象的属性值为 Object 类型,做类似的处理
*/
copyIsArray = false;
clone = src && Array.isArray( src ) ? src : [];
} else {
clone = src && jQuery.isPlainObject( src ) ? src : {};
}
// Never move original objects, clone them
/*
* 递归调用需要三个参数,
* deep(判断是否深拷贝),来源本次执行时的 deep
* clone(目标对象), 来源目标对象属性值
* copy(拷贝对象),来源拷贝对象属性值
*/
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
/*
* 不进行深拷贝,同时属性值不为 undefined,直接将属性值赋值给目标对象的同名属性
*/
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
underscore 中 _.clone()
相关代码如下:
// Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
代码很简单:
_.isObject(obj)
判断参数 obj
是否为引用类型,非引用类型直接返回_.isArray(obj)
判断参数 obj
是否为数组,如果是数组,返回值为 obj.slice()
,否则返回值为 _.extend({}, obj)
。_.isObject(obj)
和 _.isArray(obj)
的代码如下,以后我们做类型判断的时候也可以借鉴 underscore 的做法
var nativeIsArray = Array.isArray;
// Is a given value an array?
// Delegates to ECMA5's native Array.isArray
_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) === '[object Array]';
};
// Is a given variable an object?
_.isObject = function(obj) {
var type = typeof obj;
return type === 'function' || type === 'object' && !!obj;
};
判断一个变量是否为数组,首先考虑使用 ES5 提供的方法 Array.isArray()
,详细用法可以查看 MDN 中的解释。
在不支持 Array.isArray()
的浏览器上,使用 toString.call(obj) === '[object Array]'
的方式来判断,这里留个问题:为什么不用 instanceof
操作符来判断是否为数组呢?
判断一个变量是否为引用数据类型,可以使用 typeof
操作符,但是有两个特殊的变量需要注意:function
和 null
:
function fn () { console.log( 'hello world' ) };
typeof fn; // function
typeof null; // object
Array.prototype.slice():
slice()
方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。原始数组不会被修改。
当 slice()
两个参数都省略时,则从索引 0 开始提取至数组末尾:
var arr = [1, 2, [3, 4]];
var newArr = arr.slice(); // [1, 2, [3, 4]]
newArr[2].push(5);
console.log(arr); // [1, 2, [3, 4, 5]]
console.log(newArr); // [1, 2, [3, 4, 5]]
这里用到了 _.allKeys()
,这个方法返回一个由对象所有的属性名组成的数组:
// Retrieve all the property names of an object.
_.allKeys = function(obj) {
if (!_.isObject(obj)) return [];
var keys = [];
for (var key in obj) keys.push(key);
// Ahem, IE < 9.
if (hasEnumBug) collectNonEnumProps(obj, keys);
return keys;
};
_.extend()
核心代码:
// An internal function for creating assigner functions.
var createAssigner = function(keysFunc, defaults) {
return function(obj) {
var length = arguments.length;
if (defaults) obj = Object(obj);
if (length < 2 || obj == null) return obj;
for (var index = 1; index < length; index++) {
var source = arguments[index],
keys = keysFunc(source),
l = keys.length;
for (var i = 0; i < l; i++) {
var key = keys[i];
if (!defaults || obj[key] === void 0) obj[key] = source[key];
}
}
return obj;
};
};
// Extend a given object with all the properties in passed-in object(s).
_.extend = createAssigner(_.allKeys);
看起来有些复杂,我们可以做一些形式上的改造。
createAssigner()
的返回值是一个方法,另外在 _.extend = createAssigner(_.allKeys);
中,只传入了第一个参数 keysFunc
,没有传入第二个参数 defaults
,即为 undefined
。
因此,将参数代入之后,可将上面代码改写如下:
_.extend = function(obj) {
var length = arguments.length;
if (undefined) obj = Object(obj); // 可以忽略此行
if (length < 2 || obj == null) return obj;
for (var index = 1; index < length; index++) {
var source = arguments[index],
keys = _.allKeys(source),
l = keys.length;
for (var i = 0; i < l; i++) {
var key = keys[i];
if (!undefined || obj[key] === void 0) obj[key] = source[key];
}
}
return obj;
};
分析:
obj
,但在实际使用中,可以传入多个参数_.extend({}, obj)
,即将 obj
的所有属性都复制一份到 {}
中_.extend({}, obj1, obj2)
。这才是对参数进行遍历的意义所在(集众家之所长),但是要注意参数的先后顺序。如果仅仅是为了拷贝一个对象:_.extend({}, obj)
,直接遍历第二个参数 obj
的属性即可。最后,貌似一直没有看到深拷贝的方法,emmm
参考资料:
##test002
先来看看 JavaScript
中两种数据类型有何异同。
基本类型和引用类型的保存方式不同。
基本数据类型是按值访问的。基本数据类型的值保存在栈内存中,可以直接对其操作。基本数据类型包含 5 种:Undefined
、 Null
、 Boolean
、Number
和 String
。
引用类型的值是按引用访问的。引用类型的值保存在堆内存中,另外在栈内存中会有一个引用指针指向堆内存中的对象,变量中保存的实际上是一个指针。在操作对象时,实际上是在操作对象的引用指针而不是实际的对象。
另外,基本类型和引用类型的复制方式也不同。
如果从一个变量向另一个变量复制基本类型的值,会在栈内存中创建一个新值,然后把值复制到新变量的位置上。例如:
var num1 = 5;
var num2 = num1;
现在,将 num1
的值复制给 num2
,两个变量中的值相同,但是 num2
的值只是 num1
的值的一个副本,因此两者是相互独立的,不会互相影响。
当一个变量向另一个变量复制引用类型的值,同样也会将储存在变量中的值复制一份到为新变量分配的空间中。但是这个值实际上是一个指针,指向储存在堆内存中的一个对象。复制结束后,两个变量存储的指针指向同一个对象,因此改变其中一个变量,就会影响到另一个变量。
var obj1 = { name: 'js' }
var obj2 = obj1;
obj2.name = 'jquery';
console.log( obj1.name ); // jquery
由此可见,基本数据类型的复制非常简单,直接使用赋值运算即可,无副作用。然而引用类型的复制则不能直接使用赋值运算,否则操作的仍是同一个对象,毫无意义。
故下面讨论的拷贝都是针对引用数据类型而言。
我们说的复制,其实就是希望得到一个和原有对象有相同键值对集合(属性)的新对象,那么我们可以直接遍历对象,将键值对都储存在一个新的对象下,这样新对象和原对象就有一样的键值对集合(属性),也就达到我们的目标。
等一下,这里有个问题,如果某个属性值为引用类型,储存的值为对应的引用指针,则仍然会出现新变量和原有变量相互影响的问题。
以数组为例,若数组中元素都为基本数据类型:
第一步,遍历原数组,单独拷贝其中元素:
var arr = [ 1, 2, 3 ];
var newArr = [];
arr.forEach(function (item, index) {
newArr[index] = item;
})
console.log(arr); // [1, 2, 3]
console.log(newArr); // [1, 2, 3]
第二步,修改新数组:
newArr.push(4);
console.log(arr); // [1, 2, 3]
console.log(newArr); // [1, 2, 3, 4]
可以看到,修改 newArr
,原数组 arr
并未发生修改。
同样以数组为例,若数组中存在引用类型的元素:
第一步,遍历进行拷贝
var arr = [ 1, 2, [ 3, 4 ] ];
var newArr = [];
arr.forEach(function (item, index) {
newArr[index] = item;
})
console.log(arr); // [1, 2, [3, 4]]
console.log(newArr); // [1, 2, [3, 4]]
第二步,修改新数组中嵌套的数组
newArr[2].push(5);
console.log(arr); // [1, 2, [3, 4, 5]]
console.log(newArr); // [1, 2, [3, 4, 5]]
我们发现,无论是 arr
还是 newArr
都发生了变化。
当属性值为基本数据类型时,我们拷贝出来的新对象和原对象互不影响,当属性值为引用类型时,新对象和原对象在修改引用类型的属性值时相互影响。
所以说这种拷贝方式不够彻底,即浅拷贝。
现在我们封装一个同时适用于 Array
和 Object
类型的浅拷贝的方法:
function shallowCopy (obj) {
if (typeof obj !== 'object') return obj;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
注意几点:
obj
的类型来判断新建一个空数组或者空对象hasOwnProperty()
过滤出对象实例的属性上面演示了浅拷贝,浅拷贝存在的问题是引用类型的属性也是引用类型,但其实最终引用类型的键值也是由基本类型组成的。
如 var person = { name: 'jake' }
中 person
是引用类型,但是 person
的属性名和属性值都是基本类型。
所以如果我们对其进行递归浅拷贝,总会拷贝到键值均为基本数据类型的那一步。
具体代码如下:
function deepCopy (obj) {
if ( typeof obj !== 'object' ) return obj;
var newObj = obj instanceof Array ? [] : {};
for ( var key in obj ) {
if ( obj.hasOwnProperty( key ) ) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy( obj[key] ) : obj[key];
}
}
return newObj;
}
现在我们来测试一下:
var arr = [ 1, 2, [ 3, 4 ] ];
var newArr = deepCopy(arr);
newArr[2].push(5);
console.log( arr[2] ); // [3, 4]
console.log( newArr[2] ); // [3, 4, 5]
此时尽管 arr
中有引用类型的元素,通过深拷贝(递归浅拷贝)得到新对象 newArr
之后,修改其引用类型的属性可以发现,arr
和 newArr
不再互相影响,所以这种递归拷贝的方式叫做深拷贝。
上面分别总结了浅拷贝和深拷贝的方法,但是这两个方法的功能以及代码都有很大的相似度,我们可以考虑将它们封装成一个方法,通过多传入一个参数区分深拷贝和浅拷贝,如:extend( [deep], obj )
。
大致思路如下:
deep
为布尔类型,区分深浅拷贝,可忽略,忽略时视为浅拷贝(即默认值 false
)deep
那么第二个参数是拷贝的目标对象,如果忽略 deep
参数,那么第一个参数就是拷贝的目标对象。deep
判断是否进行深拷贝。代码如下:
function extend() {
var deep = false;
var target = arguments[0];
var newObj, copy;
if ( typeof target == 'boolean' ) {
deep = target;
target = arguments[1];
}
newObj = target instanceof Array ? [] : {};
if ( typeof target !== 'object' ) return target;
for ( var key in target ) {
if ( target.hasOwnProperty( key ) ) {
copy = target[ key ];
newObj[key] = deep && typeof copy === 'object' ? extend(deep, copy) : copy;
}
}
return newObj;
}
以数组为例测试一下:
var arr = [ 1, 2, [ 3, 4 ] ];
var newArr = extend(false, arr);
var newArr2 = extend(true, arr);
newArr[2].push(5);
console.log( arr[2] ); // [1, 2, [3, 4, 5]]
console.log( newArr[2] ); // [1, 2, [3, 4, 5]]
console.log( newArr2[2] ); // [1, 2, [3, 4]]
和预期一样,Good Job!
参考资料:
title: Ubuntu 安装 LAMP 环境
tags:
[toc]
安装开发环境亦或部署环境,向来不是一件容易的事情。
httpd.conf
,其实就是 apache2.conf
apt-get install mysql-server
apt-get install mysql-client
apt-get install libmysqlclient-dev
mysql -u roo t -p
exit
apt-get install apache2
/var/www/
localhost
地址查看 Apache 的默认页面):
/etc/init.d/apache2 start
/etc/init.d/apache2 restart
/etc/init.d/apache2 stop
apt-get install php
php -v
‘test’
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.