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

分析一:jQuery的无new构建

2016-05-25 14:56 429 查看
JavaScript是函数式语言,函数可以实现类,类就是面向对象编程中最基本的概念



var aQuery = function(selector, context) {
//构造函数
}
aQuery.prototype = {
//原型
name:function(){},
age:function(){}
}

var a = new aQuery();

a.name();




这是常规的使用方法,显而易见jQuery不是这样玩的

jQuery没有使用new运行符将jQuery显示的实例化,还是直接调用其函数

按照jQuery的抒写方式

$().ready()
$().noConflict()


要实现这样,那么jQuery就要看成一个类,那么$()应该是返回类的实例才对

所以把代码改一下:



var aQuery = function(selector, context) {
return new aQuery();
}
aQuery.prototype = {
name:function(){},
age:function(){}
}




通过new aQuery(),虽然返回的是一个实例,但是也能看出很明显的问题,死循环了!

 

那么如何返回一个正确的实例?

在javascript中实例this只跟原型有关系

那么可以把jQuery类当作一个工厂方法来创建实例,把这个方法放到jQuery.prototye原型中



var aQuery = function(selector, context) {
return  aQuery.prototype.init();
}
aQuery.prototype = {
init:function(){
return this;
}
name:function(){},
age:function(){}
}




当执行aQuery() 返回的实例:





很明显aQuery()返回的是aQuery类的实例,那么在init中的this其实也是指向的aQuery类的实例

问题来了init的this指向的是aQuery类,如果把init函数也当作一个构造器,那么内部的this要如何处理?



var aQuery = function(selector, context) {
return  aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
this.age = 18
return this;
},
name: function() {},
age: 20
}

aQuery().age  //18




这样的情况下就出错了,因为this只是指向aQuery类的,所以需要设计出独立的作用域才行

 

jQuery框架分隔作用域的处理

jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},


很明显通过实例init函数,每次都构建新的init实例对象,来分隔this,避免交互混淆

那么既然都不是同一个对象那么肯定又出现一个新的问题

例如:



var aQuery = function(selector, context) {
return  new aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
this.age = 18
return this;
},
name: function() {},
age: 20
}

//Uncaught TypeError: Object [object Object] has no method 'name'
console.log(aQuery().name())




抛出错误,无法找到这个方法,所以很明显new的init跟jquery类的this分离了

 

怎么访问jQuery类原型上的属性与方法?

     做到既能隔离作用域还能使用jQuery原型对象的作用域呢,还能在返回实例中访问jQuery的原型对象?

实现的关键点

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


通过原型传递解决问题,把jQuery的原型传递给jQuery.prototype.init.prototype

换句话说jQuery的原型对象覆盖了init构造器的原型对象

因为是引用传递所以不需要担心这个循环引用的性能问题



var aQuery = function(selector, context) {
return  new aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
return this;
},
name: function() {
return this.age
},
age: 20
}

aQuery.prototype.init.prototype = aQuery.prototype;

console.log(aQuery().name()) //20




百度借网友的一张图,方便直接理解:

fn解释下,其实这个fn没有什么特殊意思,只是jQuery.prototype的引用



 
通过new jQuery.fn.init() 构建一个新的对象,拥有init构造器的prototype原型对象的方法
通过改变prorotype指针的指向,让这个新的对象也指向了jQuery类的原型prototype
所以这样构建出来的对象就继续了jQuery.fn原型定义的所有方法了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: