首页 > 编程语言 >深入学习jquery源码之arguments和callee

深入学习jquery源码之arguments和callee

时间:2023-02-23 22:03:20浏览次数:40  
标签:jquery jQuery return selector length 源码 arguments context


深入学习jquery源码之arguments

js 中的函数其实是对象,函数名是对 Function 对象的引用,arguments这个对象不能显式创建,arguments对象只有函数开始时才可用。

每创建一个函数,该函数就会隐式创建一个arguments对象,他包含有实际传入参数的信息。

length   检测实际传入参数的个数
callee   对本身的调用
访问传入参数的具体的值。([下标])

参数个数不确定所以就直接调用arguments对象访问传递的参数

jQuery给自己扩展属性的方法,extend方法挂载在jQuery和jQuery.fn两个不同对象上方法,但在jQuery内部代码实现的是相同的,只是功能却不太一样;

jQuery.fn = jQuery.prototype = {
// The current version of jQuery being used
jquery: version,

constructor: jQuery,

// Start with an empty selector
selector: "",

// The default length of a jQuery object is 0
length: 0,

toArray: function () {
return slice.call(this);
},

// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function (num) {
return num != null ?

// Return just the one element from the set
(num < 0 ? this[num + this.length] : this[num]) :

// Return all the elements in a clean array
slice.call(this);
},

// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function (elems) {

// Build a new jQuery matched element set
var ret = jQuery.merge(this.constructor(), elems);

// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;

// Return the newly-formed element set
return ret;
},

// Execute a callback for every element in the matched set.
// (You can seed the arguments with an array of args, but this is
// only used internally.)
each: function (callback, args) {
return jQuery.each(this, callback, args);
}

// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
push: push,
sort: deletedIds.sort,
splice: deletedIds.splice
};

jQuery.extend = jQuery.fn.extend = function () {
var src, copyIsArray, copy, name, options, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;

// Handle a deep copy situation
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)
if (typeof target !== "object" && !jQuery.isFunction(target)) {
target = {};
}

// extend jQuery itself if only one argument is passed
if (i === length) {
target = this;
i--;
}

for (; i < length; i++) {
// Only deal with non-null/undefined values
if ((options = arguments[i]) != null) {
// Extend the base object
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
if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];

} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}

// Never move original objects, clone them
target[name] = jQuery.extend(deep, clone, copy);

// Don't bring in undefined values
} else if (copy !== undefined) {
target[name] = copy;
}
}
}
}

// Return the modified object
return target;
};

jQuery.extend() (把两个或者更多的对象合并到第一个当中)。扩展也就是所谓的静态方法,只跟这个 类 本身有关。跟你具体的实例化对象是没关系的。

jQuery.fn.extend() (把对象挂载到jQuery的prototype属性,来扩展一个新的jQuery实例方法)

jQuery.fn = jQuery.prototype = {
init:funtion(selector,context){
//.....

}
}

jQuery.fn.extend拓展的是jQuery对象(原型的)的方法,对象是啥?就是类的实例化嘛,例如$("#abc") ,$(div)。jQuery.fn.extend拓展的方法,你得用在jQuery对象上面才行

// Initialize a jQuery object


// A central reference to the root jQuery(document)
var rootjQuery,

// Use the correct document accordingly with window argument (sandbox)
document = window.document,

// A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
// Strict HTML recognition (#11290: must start with <)
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,

init = jQuery.fn.init = function (selector, context) {
var match, elem;

// HANDLE: $(""), $(null), $(undefined), $(false)
if (!selector) {
return this;
}

// Handle HTML strings
if (typeof selector === "string") {
if (selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [null, selector, null];

} else {
match = rquickExpr.exec(selector);
}

// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {

// HANDLE: $(html) -> $(array)
if (match[1]) {
context = context instanceof jQuery ? context[0] : context;

// scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge(this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
));

// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
for (match in context) {
// Properties of context are called as methods if possible
if (jQuery.isFunction(this[match])) {
this[match](context[match]);

// ...and otherwise set as attributes
} else {
this.attr(match, context[match]);
}
}
}

return this;

// HANDLE: $(#id)
} else {
elem = document.getElementById(match[2]);

// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if (elem && elem.parentNode) {
// Handle the case where IE and Opera return items
// by name instead of ID
if (elem.id !== match[2]) {
return rootjQuery.find(selector);
}

// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}

this.context = document;
this.selector = selector;
return this;
}

// HANDLE: $(expr, $(...))
} else if (!context || context.jquery) {
return (context || rootjQuery).find(selector);

// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor(context).find(selector);
}

// HANDLE: $(DOMElement)
} else if (selector.nodeType) {
this.context = this[0] = selector;
this.length = 1;
return this;

// HANDLE: $(function)
// Shortcut for document ready
} else if (jQuery.isFunction(selector)) {
return typeof rootjQuery.ready !== "undefined" ?
rootjQuery.ready(selector) :
// Execute immediately if ready is not present
selector(jQuery);
}

if (selector.selector !== undefined) {
this.selector = selector.selector;
this.context = selector.context;
}

return jQuery.makeArray(selector, this);
};

// Give the init function the jQuery prototype for later instantiation
init.prototype = jQuery.fn;

// Initialize central reference
rootjQuery = jQuery(document);

 

js中国每个函数都会有一个Arguments对象实例arguments,它引用着函数的实参,arguments.length为函数实参个数,arguments.callee引用函数自身。

在js中 不需要明确指出参数名,就能访问它们

function test() {
var s = "";
for (var i = 0; i < arguments.length; i++) {
alert(arguments[i]);
s += arguments[i] + ",";
}
return s;
}
test("name", "age")

输出结果:

name,age

arguments本身并不是数组而是对象,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数,函数的实参集合,这里的实参是重点,就是执行函数时实际传入的参数的集合。​​arguments​​​类似​​Array​​​但它不是一个​​Array​

​arguments有length属性,可以用arguments[length]显示调用​

[].slice.call(arguments)或者Array.prototype.slice.call(arguments),就是截取(更重要的是获取,slice是得到子数组)函数的参数,然后让arguments等“伪数组”也可以使用数组的各种方法。

var deletedIds = [];

var slice = deletedIds.slice;

var
version = "1.11.3",

// Define a local copy of jQuery
jQuery = function (selector, context) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init(selector, context);
}

jQuery.fn = jQuery.prototype = {
// The current version of jQuery being used
jquery: version,

constructor: jQuery,

// Start with an empty selector
selector: "",

// The default length of a jQuery object is 0
length: 0,

slice: function () {
return this.pushStack(slice.apply(this, arguments));
}
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
push: push,
sort: deletedIds.sort,
splice: deletedIds.splice
};

 

callee属性,返回正被执行的Function 对象,也就是所指定的 Function 对象的正文。callee 属性是 arguments 对象的一个成员,仅当相关函数正在执行时才可用。
callee 属性的初始值就是正被执行的 Function 对象,这允许匿名的递归函数。

var sum = function (n) {
if (1 == n) {
return 1;
} else {
return n + arguments.callee(n - 1);
}
}
alert(sum(6));

通俗一点就是,arguments此对象大多用来针对同个方法多处调用并且传递参数个数不一样时进行使用。根据arguments的索引来判断执行的方法。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

标签:jquery,jQuery,return,selector,length,源码,arguments,context
From: https://blog.51cto.com/u_11837698/6081939

相关文章

  • 深入学习jquery源码之filter()与find()
    深入学习jquery源码之filter()与find()filter(expr|obj|ele|fn)概述筛选出与指定表达式匹配的元素集合。这个方法用于缩小匹配的范围。用逗号分隔多个表达式参数expr Strin......
  • 深入学习jquery源码之prop()与removeProp()
    深入学习jquery源码之prop()与removeProp()prop(name|properties|key,value|fn)概述获取在匹配的元素集中的第一个元素的属性值。随着一些内置属性的DOM元素或window对象,如......
  • 深入学习jquery源码之addClass()和toggleClass()与hasClass()
    深入学习jquery源码之addClass()和toggleClass()与hasClass()addClass(class|fn)概述为每个匹配的元素添加指定的类名。参数class String一个或多个要添加到元素中的CSS类......
  • 深入学习jquery源码之siblings()和children()与contents()
    深入学习jquery源码之siblings()和children()与contents()siblings([expr])概述取得一个包含匹配的元素集合中每一个元素的所有唯一同辈元素的元素集合。可以用可选的表达式......
  • 深入学习jquery源码之jQuery中高质量的代码
    深入学习jquery源码之jQuery中高质量的代码1、this指向的问题 functionStudent(name,age,grade,school){Person.apply(this,arguments);}他就具备了Pe......
  • 深入学习jquery源码之next()和nextAll()与nextUntil()
    深入学习jquery源码之next()和nextAll()与nextUntil()next([expr])概述取得一个包含匹配的元素集合中每一个元素紧邻的后面同辈元素的元素集合。这个函数只返回后面那个紧邻......
  • 深入学习java源码之Math.sin()与 Math.sqrt()
    深入学习java源码之Math.sin()与Math.sqrt()native关键字凡是一种语言,都希望是纯。比如解决某一个方案都喜欢就单单这个语言来写即可。Java平台有个用户和本地C代码进行互......
  • 深入学习jquery源码之parent()和parents()与parentsUntil()
    深入学习jquery源码之parent()和parents()与parentsUntil()parent([expr])概述取得一个包含着所有匹配元素的唯一父元素的元素集合。你可以使用可选的表达式来筛选。参数exp......
  • 深入学习jquery源码之prev()和prevAll()与prevUntil()
    深入学习jquery源码之prev()和prevAll()与prevUntil()prev([expr])概述取得一个包含匹配的元素集合中每一个元素紧邻的前一个同辈元素的元素集合。可以用一个可选的表达式进......
  • slate源码解析(一)- 序言
    笔者从大学时期就开始接触的前端,在刚去实习的时候就被导师安排去做内网的一个小富文本工具。之后从毕业后干的第一份工作游戏客户端,到现在做着可视化相关的前端工作,都有在......