jQuery使用上的几大特点:
1、使用$()函数方式直接生成jQuery对象
2、链式调用(在函数的结尾返回this,this的值是根据函数运行的时候确定的)
无new函数创建对象:把jQuery.prototype.init.prototype = jQuery.prototype
jQuery.fn,它实际上是 prototype 的一个引用,指向 jQuery.prototype 。好处:书写简洁
var jQuery = function(){
return new jQuery.fn.init();
}
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function(){
this.jquery = 3.0;
return this;
},
each: function(){
console.log('each');
return this;
}
}
jQuery.fn.init.prototype = jQuery.fn;
jQuery().each().each();
// 'each'
// 'each'
1、$.globalEval( code )-----全局性的执行一段代码
var name = "全局变量";
$(function () {
function test(){
var name = "局部变量";
alert(name); // 局部变量
eval( "alert(name);" ); // 局部变量
$.globalEval( "alert(name);" ); // 全局变量
}
test();
})
大致思路:首先创建script元素;然后将传进来的参数赋给script.text属性;最后采用链式写法,将创建的script对象添加到head对象里面(这时候就执行JS代码),然后再将添加的script对象删除。
// 部分源码
globalEval: function(a) {
p(a)
}
function p(a, b) {
b = b || d; //b没有传进来*(只传了一个参数),则b=document
var c = b.createElement("script");
c.text = a,
b.head.appendChild(c).parentNode.removeChild(c)
}
2、$.extend()---用于将一个或多个对象的内容合并到目标对象(给jQuery扩展静态属性和方法)-----默认是浅拷贝,返回目标对象
1)扩展到对象层面--jQuery.extend(),扩展的是静态方法,可以直接使用$调用;
2)扩展到选择器函数对象层面----jQuery.fn.extend(),扩展的方法是实例的方法,由$('#id名')或者$('.类名')调用
具体作用:
1)将两个或更多对象的内容合并到第一个对象(如果只有一个参数对象,则将其扩展到jQuery对象上)---实现默认字段的覆盖
jQuery.extend( target [, object1 ] [, objectN ] )
function getOpt(target, obj1, obj2, obj3){
$.extend(target, obj1, obj2, obj3);
return target;
}
var _default = {
name : 'wenzi',
age : '25',
sex : 'male'
}
var obj1 = {
name : 'obj1'
}
var obj2 = {
name : 'obj2',
age : '36'
}
var obj3 = {
age : '67',
sex : {'error':'sorry, I dont\'t kown'}
}
getOpt(_default, obj1, obj2, obj3); // {name: "obj2", age: "67", sex: {error: "sorry, I dont't kown"}}
2)为jQuery或者jQuery原型扩展方法或属性----如果extend()函数只传一个对象参数,jQuery对象本身被默认为目标对象,浅拷贝
$.extend({
_name : 'wenzi',
_getName : function(){
return this._name;
}
})
$._name; // wenzi
$._getName(); // wenzi
3)深度拷贝和浅度拷贝----若第一个参数是boolean类型,且值是true(深拷贝)或者false(浅拷贝),把第二个参数作为目标参数进行合并
jQuery.extend( [deep ], target, object1 [, objectN ] )
//深复制
var obj = {name:'wenzi', score:80};
var obj1 = {score:{english:80, math:90}}
$.extend(true, obj, obj1);
obj.score.english = 10;
console.log(obj.score.english); // 10
console.log(obj1.score.english); // 80
//浅复制
var obj = {name:'wenzi', score:80};
var obj1 = {score:{english:80, math:90}}
$.extend(false, obj, obj1);
obj.score.english = 10;
console.log(obj.score.english); // undefined
console.log(obj1.score.english); // 80
jQuery中的extend()实现原理
大致过程:对后一个参数进行循环,然后把后面参数上所有的字段都给了第一个字段,若第一个参数里有相同的字段,则进行覆盖操作,否则就添加一个新的字段
1)对第一个参数做判断,如果不是Boolean类型,且只有一个参数,那么就把jQuery作为target,然后把第一个参数上的字段都赋给target,最后返回target(浅拷贝);如果有多于一个参数,那么第一个参数就是target,然后把后面参数的字段都赋给target,最后返回target(浅拷贝)
2)第一个参数是boolean类型,表示深浅拷贝,true表示深拷贝,false表示浅拷贝。只有两个参数,那么就把jQuery作为target,把第二个参数的字段赋给target,然后返回target。多于两个参数,把第二个参数作为target,然后把后面的参数的字段赋给target,最后面返回target.
// 为与源码的下标对应上,我们把第一个参数称为`第0个参数`,依次类推
jQuery.extend = jQuery.fn.extend = function() {
var options,
name,
src,
copy,
copyIsArray,
clone,
target = arguments[0] || {}, // 默认第0个参数为目标参数
i = 1, // i表示从第几个参数开始将目标参数与其进行合并,默认从第1个参数开始向第0个参数进行合并
length = arguments.length,
deep = false; // 默认为浅拷贝
// 1、判断第0个参数的类型,若第0个参数是boolean类型,则获取其为true还是false
// 同时将第1个参数作为目标参数,i从当前目标参数的下一个
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
// 如果第一个参数是Boolean类型
target = arguments[ i ] || {};
i++;
}
///2、判断目标参数的类型,若目标参数既不是object类型,也不是function类型,则为目标参数重新赋值空对象
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
///3、若目标参数后面没有参数了,如$.extend({_name:'wenzi'}), $.extend(true, {_name:'wenzi'})
// 则目标参数即为jQuery本身,而target表示的参数不再为目标参数
// Extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
// 4、从第i个参数开始遍历
for ( ; i < length; i++ ) {
// 获取第i个参数,且该参数不为null和undefind,在js中null和undefined,如果不区分类型,是相等的,null==undefined为true,
// 因此可以用null来同时过滤掉null和undefind
// 比如$.extend(target, {}, null);中的第2个参数null是不参与合并的
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
///5、使用for~in获取该参数中所有可枚举的属性
// Extend the base object
for ( name in options ) {
src = target[ name ]; // 目标参数中name字段的值
copy = options[ name ]; // 当前参数中name字段的值,有可能是值,Object,Array
///6、若参数中属性的值就是目标参数,停止赋值,进行下一个字段的赋值
// 这是为了防止无限的循环嵌套,我们把这个称为,在下面进行比较详细的讲解
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
///7、若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进行深度赋值
// Recurse if we're merging plain objects or arrays
// jQuery.isPlainObject()返回值为Boolean类型,如果指定的参数是纯粹的对象,则返回true,否则返回false
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
// 若当前参数中name字段的值为Array类型
// 判断目标参数中name字段的值是否存在,若存在则使用原来的,否则进行初始化
if ( copyIsArray ) {
//被复制的属性的值类型为Array
copyIsArray = false;
//判断该字段在target对象是否存在,存在且为Array,则直接使用原对象,否则创建空的Array
clone = src && jQuery.isArray(src) ? src : [];
}else{
// 被复制的属性的值得类型为Object
//判断该字段在target对象是否存在,若存在且为Object则直接使用,否则创建空的Object
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// 递归处理,此处为2.2
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// deep为false,则表示浅度拷贝,直接进行赋值
// Don't bring in undefined values
}else if ( copy !== undefined ) {
// 若copy是简单的类型且存在值,则直接进行赋值
// 若原对象存在name属性,则直接覆盖掉;若不存在,则创建新的属性
target[ name ] = copy;
}
}
}
}
// 返回修改后的目标参数
// Return the modified object
return target;
};
3、jquery中type()-----$.type(任意类型对象)
作用---------确定JavaScript内置对象的类型,并返回小写形式的字符串类型名称
//1、对于对象是undefined null类型 ,如果是对象上没有的属性,则返回'undefined' 结果都为true
console.log($.type( undefined ) === "undefined");
console.log($.type() === "undefined");
console.log($.type( window.notDefined ) === "undefined");
console.log($.type( null ) === "null");
// 2、js中内置的对象
console.log( jQuery.type( true ) === "boolean" );
console.log( jQuery.type( new Boolean() ) === "boolean" );
console.log( jQuery.type( 3 ) === "number");
console.log( jQuery.type( "test" ) === "string" );
console.log( jQuery.type( function(){} ) === "function");
console.log( jQuery.type( [] ) === "array" );
console.log( jQuery.type( new Date() ) === "date");
console.log( jQuery.type( new Error() ) === "error" );
console.log( jQuery.type( Symbol() ) === "symbol" );
console.log( jQuery.type( /test/ ) === "regexp");
console.log( jQuery.type( {} ) === "object");
//因为 jQuery 用的是 toString 方法,所以需要有一个 class2type 的对象用来转换
var class2type = {
"[object Boolean]": "boolean",
"[object Number]": "number",
"[object String]": "string",
"[object Function]": "function",
"[object Array]": "array",
"[object Date]": "date",
"[object RegExp]": "regexp",
"[object Object]": "object",
"[object Error]": "error",
"[object Symbol]": "symbol",
"[object Set]": "set",
"[object Map]": "map"
}
var toString = Object.prototype.toString;
jQuery.type = function (obj) {
if (obj == null) {
return obj + "";
}
return
typeof obj === "object" || typeof obj === "function" ?
class2type[toString.call(obj)] || "object" :
typeof obj;
}
原理:对于null或undefined类型直接返回,如果是object或function类型则调用Object.prototype.toString.call()函数来判断参数的类型
4、jquery中的isPlainObject(object)----判断指定参数是否是一个纯粹的对象
//object ---任意类型
$.isPlainObject( object )
var getProto = Object.getPrototypeOf; //获取父对象---原型对象
var hasOwn = class2type.hasOwnProperty; //自身是否具有指定的属性,不包括原型上的属性,
var fnToString = hasOwn.toString;
var ObjectFunctionString = fnToString.call( Object );
jQuery.isPlainObject = function (obj) {
var proto, Ctor;
// 排除 underfined、null 和非 object 情况
if (!obj || toString.call(obj) !== "[object Object]") {
return false;
}
// 获取原型对象
proto = getProto(obj);
// Objects with no prototype (e.g., `Object.create( null )`) are plain
if (!proto) {
return true;
}
// Objects with prototype are plain iff they were constructed by a global Object function
Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
}
5、$.isArray = Array.isArray( obj )-----判断参数是否是数组
实现原理:Object.prototype.toString.call(obj) === '[object Array]'
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
6、$.fn.css()-----设置或返回被选元素的一个或多个样式属性
例子:
//1、返回指定的 CSS 属性的值
css("propertyname");
$("p").css("background-color");
// 设置 CSS 属性
//2、单个css属性
css("propertyname","value");
$("p").css("background-color","yellow");
//3、设置多个 CSS 属性
css({"propertyname":"value","propertyname":"value",...});
$("p").css({"background-color":"yellow","font-size":"200%"});
//css()只有一个参数,参数为字符串则通过getComputedStyle(obj)['attr']返回该属性的值;为
// 对象则再次调用该函数css
//若 css 有两个参数,则为元素的style属性赋值
css : function(attr,val){
for(var i = 0; i < this.length; i++){
if(val == undefined){
if(Object.prototype.toString.call(attr) === '[object Object]'){
for(var key in attr){
this.css(key, attr[key]);
}
}else if(typeof attr === 'string'){
return getComputedStyle(this[i])[attr];
}
}else{
this[i].style[attr] = val;
}
}
}
7、jquery中的merge()----合并两个数组内容到第一个数组
// first---Array类型 第一个用于合并的数组,合并后将包含第二个数组的内容
// Array类型 第二个用于合并的数组,该数组不会被修改
$.merge( first, second )
var arr1 = [ 0, 1, 2 ];
var arr2 = [ 2, 3, 4 ];
$.merge( arr1, arr2);
console.log(arr1); //[0, 1, 2, 2, 3, 4]
console.log(arr2); //[2, 3, 4]
$.merge( $.merge([], arr1), arr2); //这样就不会修改原来的数组对象了
源码:对第二个参数数组进行遍历,添加到第一个参数数组里面,并修改第一个参数数组的length属性
merge: function( first, second ) {
var len = +second.length,
j = 0,
i = first.length;
for ( ; j < len; j++ ) {
first[ i++ ] = second[ j ];
}
first.length = i;
return first;
}
8、jquery中的isArrayLike(obj)----判断参数是否为类数组
function isArrayLike(obj) {
// Support: real iOS 8.2 only (not reproducible in simulator)
// `in` check used to prevent JIT error (gh-2145)
// hasOwn isn't used here due to false negatives
// regarding Nodelist length in IE
var length = !!obj && "length" in obj && obj.length,
type = jQuery.type(obj);
if (type === "function" || jQuery.isWindow(obj)) {
return false;
}
return type === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj;
}
9、jquery中的makeArray()----将一个类似数组的对象转换为真正的数组对象
$.makeArray( object )
$(function () {
var elems = document.getElementsByTagName("div"); // 返回一个节点列表
var arr = jQuery.makeArray(elems);
arr.reverse(); //对列表的元素使用一个数组方法
$(arr).appendTo(document.body);
})
var push = [].push;
jQuery.makeArray = function (arr, results) {
var ret = results || [];
if (arr != null) {
if (isArrayLike(Object(arr))) {
jQuery.merge(ret, typeof arr === "string" ? [arr] : arr);
} else {
push.call(ret, arr);
}
}
return ret;
}
8、jquery中的each()----$.each()和$(选择器).each----each的实现采用迭代器模式
1)$(选择器).each( callback(index,val)):为每个匹配元素规定运行的函数
$(selector).each(function(index,element))
//例子
$("button").click(function(){
$("li").each(function(){
alert($(this).text())
});
});
2)$.each(arr | obj,callback(index,item)):----对数组或对象遍历
// 遍历数组
var arr = [{name:"limeng",email:"xfjylimeng"},{name:"hehe",email:"xfjylimeng"}];
$.each(arr,function(index,item){
console.log("索引:" + index + "对应值为:" + item.name); //参数index为遍历索引值,item为当前的遍历对象,可用this指代
});
var arr1 = [ "one", "two", "three", "four", "five" ];
$.each(arr1, function(index,val){ //this指向当前的遍历对象
console.log(val); //one two three four five
});
var arr2 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
$.each(arr2, function(index, val){
console.log(val[0]); //1 4 7
});
// 遍历对象
var obj = { one:1, two:2, three:3, four:4, five:5 };
$.each(obj, function(key, val) {
console.log(obj[key]); //1 2 3 4 5
});
jQuery.each()和jQuery.fn.each()的源码是一样的
原理:通过w(a)函数判断参数是否为类数组,是则通过for循环对类数组中的每个元素调用一个callback,通过call改变callback的上下文环境为当前元素;否则为对象,则通过for...in对对象的每个元素调用一个callback,通过call改变上下文环境
//返回Boolean类型的值
//判断数组是否是类数组----具有length属性和可通过index属性访问成员
//通过type()函数返回参数的类型---Object.prototype.toString.call()
function w(a) {
var b = !!a && "length" in a && a.length,
// 返回参数的类型
c = r.type(a);
return "function" !== c && !r.isWindow(a) && ("array" === c || 0 === b || "number" == typeof b && b > 0 && b - 1 in a)
}
each: function(a, b) {
//a---array || object
//b----callback(index,val)
var c, d = 0;
//是类数组
if (w(a)) {
//----array
for (c = a.length; d < c; d++){
//b----callback
if(b.call(a[d], d, a[d]) === !1){
break;
}
}
} else{
//object
for(d in a){
if (b.call(a[d], d, a[d]) === !1) {
break;
}
}
}
return a
}
9、jquery中的trim(str)----去除字符串首尾的空白字符
原理:利用String的replace()和正则表达式以及三目运算符
s = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
trim: function(a) {
return null == a ? "": (a + "").replace(s, "");
}
10、jquery中的makeArray()-----将一个类数组对象转换为真正的数组对象
类数组对象----具有length属性且不为负值;可通过数字下标访问元素。没有数组原型对象上内置的方法。jquery对象($('p')),arguments,NodeList对象(document.getElementsByNodeName('p')) 返回值----数组对象
|