您的位置:首页 > Web前端 > JQuery

jQuery的一些简单知识点(二)

2017-09-21 09:32 302 查看
1.把入口函数和框架融合,extend混入扩展静态方法,IE8中apply的兼容性问题

<body>
<script>
(function( w ) {

// 工厂
function jQuery( selector ) {
return new jQuery.fn.init( selector );
}

// 替换原型 + 原型简称
jQuery.fn = jQuery.prototype = {
constructor: jQuery
}

// 给jQuery和原型分别添加extend方法,混入方式
jQuery.extend = jQuery.fn.extend = function( obj ) {
for ( var key in obj ) {
this[ key ] = obj[ key ];
}
}

// 给jQuery添加一些静态方法
jQuery.extend({

// 去掉首尾空白字符
trim: function( str ) {

// null、undefined、NaN、0、false、''
if ( !str ) {
return str;
}

// 优先使用原生的
if ( str.trim ) {
return str.trim();
}

return str.replace( /^\s+|\s+$/g, '');

},

// 判断是不是html片段
isHTML: function( html ) {

// null、undefined、NaN、0、false、''
if ( !html ) {
return false;
}

// <.>
if( html.charAt(0) === '<' &&
html.charAt( html.length - 1 ) === '>' &&
html.length >= 3 ) {
return true;
}

return false;
},

// 判断是不是html片段
_isHTML: function( html ) {
return !!html &&
html.charAt(0) === '<' &&
html.charAt( html.length - 1 ) === '>' &&
html.length >= 3;
},

// 判断是不是函数
isFunction: function( fn ) {
if ( typeof fn === 'function' ) {
return true;
}
return false;
},

// 判断是不是函数
_isFunction: function( fn ) {
return typeof fn === 'function';
},

// 判断是不是window
isWindow: function( w ) {

// null、undefined、NaN、0、false、''
if( !w ) {
return false;
}

if( w.window === w ) {
return true;
}

return false;
},

// 判断是不是window
_isWindow: function( w ) {
return !!w && w.window === w;
},

// 判断是不是对象
isObject: function( obj ) {

// 防止typeof对null的误判
if ( obj === null ) {
return false;
}

// 如果是object或function,那就是对象
if ( typeof obj === 'object' || typeof obj === 'function' ) {
return true;
}

return false;
},

// 判断是不是字符串
isString: function( str ) {
if ( typeof str === 'string' ) {
return true;
}
return false;
},

// 判断是不是字符串
_isString: function( str ) {
return typeof str === 'string';
},

// 判断是不是真数组或伪数组
isLikeArray: function( arr ) {

// Function、window、!Object
if ( jQuery.isFunction( arr ) || jQuery.isWindow( arr ) || !jQuery.isObject( arr ) ) {
return false;
}

// 判断是不是真数组
if ( ({}).toString.call( arr ) === '[object Array]' ) {
return true;
}

// 判断是不是伪数组
if ( 'length' in arr && ( arr.length === 0 || arr.length - 1 in arr ) ) {
return true;
}

return false;
},

ready: function( fn ) {

// 先统一判断DOMContentloaded有没有触发,
// 通过document.readyState === 'complete'判断
// 如果为true,fn可以直接调用。

// 如果为false,那么判断支不支持addEventListener,
// 如果支持,绑定DOMContentLoaded事件

// 如果不支持,使用attchEvent绑定onreadystatechang事件,
// 注意,需要在里面判断document.readyState === 'complete'才执行fn。
// 防止fn多次执行。

// DOM已经构造完毕,fn可以直接执行
if ( document.readyState === 'complete' ) {
fn();
}

// 如果DOM没有构造完毕,那么判断addEventListener是否兼容
else if( document.addEventListener ) {
document.addEventListener( 'DOMContentLoaded', fn );
}

// 如果不兼容addEventListener,那么采取attachEvent的方式,
// 同时事件变为了onreadystatechange,为了防止这个事件多次触发造成的fn多次执行,
// 所以需要一个包装函数来进行过滤。
else {
document.attachEvent( 'onreadystatechange', function() {
if( document.readyState === 'complete' ) {
fn();
}
} );
}
}
});

// 这是真正的构造函数,同时把构造函数放在了原型中
var init = jQuery.fn.init = function( selector ) {

// null、undefined、NaN、0、false、''
if ( !selector ) {
return this;
}

// function
if ( jQuery.isFunction( selector ) ) {

// 打包给ready静态方法处理
jQuery.ready( selector );
}

// string ==> ( html || selector )
else if( jQuery.isString( selector ) ) {

// 为了用户友好体验,先去掉首尾空白字符
selector = jQuery.trim( selector );

// html
if( jQuery.isHTML( selector ) ) {

// 利用一个临时的div来创建DOM,
// 然后把创建好的DOM依次push给实例。
var tempDiv = document.createElement( 'div' );
tempDiv.innerHTML = selector;
[].push.apply( this, tempDiv.childNodes );

}

// selector
else {

try {
[].push.apply( this, document.querySelectorAll( selector ) );
}catch(e) {
// 如果报错了,那么手动补一个length属性,代表没有获取到任何元素
this.length = 0;
}
}
}

// array || likeArray
else if( jQuery.isLikeArray( selector ) ) {
//[].push.apply( this,  selector  ); 这里,如果selector是自己写的伪数组,而不是系统的伪数组,那么在IE8中会出错,所以我们采用了[].slice.call( selector ) ,把伪数组转变为真数组。
[].push.apply( this, [].slice.call( selector ) );
}

// 其它
else {
this[0] = selector;
this.length = 1;
}
};

// 替换init的原型为工厂的原型,这样外界就可以通过工厂给实例扩展方法
init.prototype = jQuery.fn;

// 暴露工厂和工厂的简称
w.jQuery = w.$ = jQuery;

}( window ));

// 静态方法测试
console.log($._isFunction([]));
console.log($.isWindow( window ));
console.log($.isLikeArray( { length: 5 } ));
console.log($.isLikeArray( { length: 0 } ));

// 入口测试
console.log($([1, 2]));
console.log($(' script'));
console.log($(' <span>111</span><span>222</span> '));
console.log($({ 0:document.body, length:1 }));

// 测试入口对函数的支持
$(function() {
console.log($('a')); //再打印这一句
});
console.log($('bb'));    //先打印这一句
</script>
<div>
<a>1</a>
<a>2</a>
<a>3</a>
</div>
</body>


2.jQuery中静态方法Each(),数组的forEach(),以及自定义的each()的使用,以及each()中的this指向问题

<script>
var obj = {
1: 'aaa',
2: 'bbb',
3: 'ccc'
};
var arr = ['xxx', 'yyy', 'zzz'];
// jQuery中静态方法each的使用,及其中的this指向,this指的是每一个元素
$.each(obj, function(key, val) {
console.log(key, val, this);
});
$.each(arr, function(key, val) {
console.log(key, val, this);
});

// arr的原型方法forEach的使用,注意参数顺序,以及this指向问题window
arr.forEach(function(val, key) {
console.log(val, key, this); //window
});

// function each(obj,fn){
//  if ('length' in arr) {
//      for(var i=0;i<obj.length;i++){
//          fn(i,obj[i]);
//      }
//  }else{
//      for(var key in obj){
//          fn(key,obj[key]);
//      }
//  }
// };
// 自定义方法中的this也是指向window的
// each(arr, function(key, val) {
//     console.log(key, val, this); //window
// });

function each1(obj, fn) {
if ('length' in arr) {
for (var i = 0; i < obj.length; i++) {
fn.call(obj[i], i, obj[i]);
}
} else {
for (var key in obj) {
fn.call(obj[key], key, obj[key]);
}
}
};
// 自定义方法中的this也是指向每一元素对应的对象
each1(arr, function(key, val) {
console.log(key, val, this); //
});
</script>


3.遍历中断,这里最好打个断点看下函数的执行流程,加强对回调函数的理解。

function each1(obj, fn) {
if ('length' in obj) {
for (var i = 0; i < obj.length; i++) {
if (fn.call(obj[i], i, obj[i]) === false) {
break;
}
}
} else {
for (var key in obj) {
if (fn.call(obj[key], key, obj[key])===false) {
break;
}
}
}
};

// 自定义方法中的this也是指向每一元素对应的对象
each1(obj, function(key, val) {
if (val == 'bbb') {
return false;
}
console.log(key, val, this); //
});
打个比方,再调用each1()时,传入了obj和一个函数,这就好比是大boss派了一个保镖去门口监视路过门口的行人obj,保镖的任务是把每个人的编号和T-shirt上的信息告诉大boss,大boss接受到每一个人T-shirt上的信息,发现有个人的T-shirt上写的是‘bbb’,通过对讲机告诉保镖,停止监视false,立刻break.


4.模仿jQuery中map()的实现

<script>

var obj = { a: 111, b: 222, c: 333, d: 444 };
var arr = [ 'aaa', 'bbb', 'ccc', 'dddd' ];

/*
* jQ的map方法,用来遍历对象或者数组,
* 然后把遍历到了val和key值传给回调,
* 最后收集回调的返回值,构成新数组返回。
* */

/*console.log($.map(obj, function (val, key) {
console.log(val, key, this);
return val;
}));*/

// map实现
function map( obj, fn ) {

/*
* 1、先判断obj是不是数组或者伪数组,
* 2、如果是,则通过i的方式遍历这个对象
* 3、如果不是,则通过for in的方式遍历这个对象
* 4、在遍历的过程中,把每一次遍历到key和val分别传给回调。
* 5、在给回调传参的时候,需要收集回调的返回值,最后把所有的返回值构成新数组返回。
* */
var i, len, key, result = [];

if( 'length' in obj ) {
for ( i = 0, len = obj.length; i < len; i++ ) {
result.push( fn.call( obj[ i ], obj[ i ], i ) );
}
}else {
for ( key in obj ) {
result.push( fn.call( obj[ key ], obj[ key ], key ) );
}
}

return result;
}

console.log(map(obj, function (val, key) {
console.log(val, key, this);
//            return val / 100;
}));

</script>

// 给jQuery的静态方法加入map和each方法,同时,拥有在jQuery的原型中有这两个变量
jQuery.extend({

// 遍历对象或类数组
each: function( obj, fn ) {
var i, len, key;

if ( jQuery.isLikeArray( obj ) ) {
for ( i = 0, len = obj.length; i < len; i++ ) {
if ( fn.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}
}
}else {
for ( key in obj ) {
if ( fn.call( obj[ key ], key, obj[ key ] ) === false ) {
break;
}
}
}

return obj;
},

// map实现
map: function( obj, fn ) {

/*
* 1、先判断obj是不是数组或者伪数组,
* 2、如果是,则通过i的方式遍历这个对象
* 3、如果不是,则通过for in的方式遍历这个对象
* 4、在遍历的过程中,把每一次遍历到key和val分别传给回调。
* 5、在给回调传参的时候,需要收集回调的返回值,最后把所有的返回值构成新数组返回。
* */
var i, len, key, result = [];

if( 'length' in obj ) {
for ( i = 0, len = obj.length; i < len; i++ ) {
console.log('*****',fn.call( obj[ i ], obj[ i ], i ));
result.push( fn.call( obj[ i ], obj[ i ], i ) );
}
}else {
for ( key in obj ) {
result.push( fn.call( obj[ key ], obj[ key ], key ) );
}
}
console.log('-------',result);
return result;
},
...
});

// 替换原型 + 原型简称
jQuery.fn = jQuery.prototype = {
// 遍历实例
each: function( fn ) {
return jQuery.each( this, fn );
},

// 通过实例得到一个新数组
map: function( fn ) {
return jQuery.map( this, fn );
},
...
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: