内容:
- jQuery无new构建实例
- 共享原型设计
- extend源码解析
jQuery的Extend用法:
var obj1 = {
name: 'Max',
list: {
age: 21
}
};
var obj2 = {
items: {
nan: 'Ch'
},
list: {
gender: 'Male'
}
};
// 给任意对象扩展属性
var obj3 = $.extend(true, obj1, obj2);
console.log(obj3);
// 给jQuery本身扩展属性
jQuery.extend({
work: function() {
}
});
jQuery.work();
// 给jQuery对象实例扩展属性
jQuery.fn.extend({
gender: 'Male'
});
jQuery('').gender;
Code实现:
(function(root) {
var jQuery = function() {
return new jQuery.prototype.init(); // 创建jQuery的实例对象,不能写 new jQuery(),会造成循环调用
}
// jQuery原型上扩展属性
jQuery.fn = jQuery.prototype = {
init: function() {
},
css: function() {
}
};
// jQuery本身扩展和原型上扩展都调用了同一个方法 extend
jQuery.fn.extend = jQuery.extend = function(){
var target = arguments[0] || {};
var length = arguments.length;
var i = 1;
var deep = false;
var name, option, copy, src,isCopyArray, clone;
// 第一个参数是否为布尔类型:target要为第二个参数,i要从第三个参数开始循环
if(typeof target === "boolean") {
deep = target;
target = arguments[1];
i = 2;
}
// 第一个参数必须是object
if(typeof target !== 'object') {
target = {};
}
if(i === length) {
target = this;
i--;
}
// 浅拷贝, 深拷贝
//1.扩展:target = this; i = 0;length=1;
//2.浅拷贝:target = arguments[0];i=1;
//3.深拷贝:target = arguments[1];i=2;
for(; i < length; i++) {
if((option = arguments[i]) !== null) {
for(name in option) {
copy = option[name];
src = target[name];
if (deep && (jQuery.isPlainObject(copy) || (isCopyArray = jQuery.isArray(copy)))) {
if(isCopyArray) {
isCopyArray = false;
clone = src && jQuery.isArray(src) ? src : [];
}
else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
target[name] = jQuery.extend(deep, clone, copy);
}
else {
target[name] = option[name];
}
}
}
}
return target;
}
// 共享原型设计:init的原型等于jQuery的原型,这样new init()创建出来对象的原型也就是jQuery的原型
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend({
isPlainObject: function(obj) {
return toString.call(obj) === "[object Object]";
},
isArray: function(obj) {
return toString.call(obj) === "[object Array]";
}
});
root.$ = root.jQuery = jQuery; // $是jQuery的一个别名
})(this);
思考问题:
1. jQuery实际是new jQuery.fn.init()实例化对象,那么常用的方法如$.ajax,$.get是怎么实现的?
A: ajax,get等都是jQuery的静态方法;通过 jQuery.extend({ajax:…, get: ….}) 去实现;
$.extend()与$.fn.extend()的区别?
$.extend() 是向 jQuery上扩展属性,$.fn.extend() 是向jQuery的实例对象上扩展属性;可以参考下面的Code。
通过$.extend()扩展的属性,要通过jQuery.属性名来访问;
通过$.fn.extend()扩展的属性,要通过jQuery(‘selector’).属性名来访问(也就是通过jQuery的实例对象访问)。// 给jQuery本身扩展属性
jQuery.extend({
work: function() {
}
});
jQuery.work();
// 给jQuery对象实例扩展属性
jQuery.fn.extend({
gender: 'Male'
});
jQuery('').gender;
具体例子可以参考:
https://www.yuque.com/niruoanhao/cc61zh/qgw5re
1. JSON.stringify和JSON.parse() (深拷贝)
var x = {
a: 1,
b: undefined,
c: null,
d: function() {},
e: Symbol,
f: new Date,
}
var y = JSON.parse(JSON.stringify(x));
console.log(y) /*{
a: 1
c: null
f: "2019-08-30T07:11:45.286Z"
}*/
这种拷贝方法会造成值为undefined、Symbol、function的属性丢失,如果确定要拷贝的对象没有这几类值的话就放心大胆的使用吧。
2. 扩展符…
var x = {
a: 1,
b: {
c: 1
}
}
var y = {...x};
y.a = 13;
y.b.c = 15;
console.log(x) // x:{a:1,b:{c:15}}
这个结果是不是似曾相识,这和我们前面写的浅拷贝一模一样哦,所以 … 可以用来拷一层结构的数据,多层的话就得谨慎使用了。
3. object.assign
var m1 = {a:1,b:{x:1,y:2}};
var n1 = {b:{x1:3,y1:4}};
var obj1 = Object.assign(m1,n1) //obj1:{a:1,b:{x1:3,y1:4}}
浅拷贝。
思维扩展
我们使用拷贝的目的是复制一份,原来的对象保持不变,之前一直围绕如何让复制出来对象与原对象取消关联,是否可以换个思路,如冻结原对象。
freeze
var x = {a: 1,b:{c:1}}
var y = x;
Object.freeze(x);
y.a = 2;
console.log(x, y) // x:{a:1} y:{a:1}
第一个尝试案例就失败了,x,y指向同一个指针,而这个指针索引的对象被冻结,导致y的修改是无效的。经过尝试freeze只能冻结第一层结构,如x.b.c是没有冻结的,可以改变,如果想深度冻结一个对象,可以和深拷贝一样使用递归冻结。