由Jquery创建对象引发的思考

CodeCipher
• 阅读 3622

读到jquery源码时我有以下疑惑


问题1 Jquery 中创建对象的奥秘
问题2 JavaScriptthis的指向问题
问题3 return this 的作用
问题4 instanceof / 对象和类之间的关系

//代码1(Jquery 创建对象)

var iQuery=function (){
    name="iQuery";   //4
    return new iQuery.prototype.init();   //1
};
iQuery.prototype={
    init : function(){
        name="iQueryPrototypeInit";   //5
        return this;   //2
    },

    name : "iQueryPrototype"   //6
};

iQuery.prototype.init.prototype=iQuery.prototype;   //3

这时我有问题了,//1 处有无new的区别。//2 处有无 return this 的区别。 //3处的作用
在这里我通过对//代码1 进行分解来回答 问题1 到 问题4

//代码2 我将 //代码1 中的 //3 处去掉 //2 处去掉 //1 处去掉

var iQuery=function (){
    name="iQuery";
    return iQuery.prototype.init();
};
iQuery.prototype={
    init : function(){
        name="iQueryPrototypeInit";   //5
    },

    name : "iQueryPrototype"
};

iQuery().name; //结果为  VM105:1 Uncaught TypeError: Cannot read property name of undefined(…)

分析: iQuery.prototype.init() 是调用了init函数,由于函数没有返回值,所以只返回了控制 return iQuery.prototype.init() 也没有返回值iQuery().name;会有以上错误提示

//代码3

var iQuery=function (){
    name="iQuery";   //4
    return new iQuery.prototype.init();   //1
};
iQuery.prototype={
    init : function(){
        name="iQueryPrototypeInit";   //5
    },

    name : "iQueryPrototype"   //6
};

iQuery().name;  //结果为  undefined 这里并不提示错误,而是说name没有定义;

分析: //4处 nameiQuery 的局部变量,//5 处nameinit的局部变量。
执行iQuery()时创建了一个init的对象,这时init是构造函数,执行时流程

1 创建一个对象
2 返回新建的对象
这就是有无 new 的区别

//代码4 多了个this

    var iQuery=function (){
        name="iQuery";   //4
        return new iQuery.prototype.init();   //1
    };
    iQuery.prototype={
        init : function(){
            this.name="iQueryPrototypeInit";   //5
        },
    
        name : "iQueryPrototype"   //6
    };

iQuery().name;  //结果为  `iQueryPrototypeInit`

分析: 执行 iQuery().name;执行流程

1 创建一个对象
2 让 this 引用这个对象
3 为 this 所引用的对象添加属性 name
4 返回 this 所引用的对象

iQuery() instanceof iQuery  //false
iQuery() instanceof iQuery.prototype  //VM125:1 Uncaught TypeError: Right-hand side of 'instanceof' is not callable(…)

iQuery.prototype 是一个对象 instanceof 右边必须是类,即函数名

iQuery() instanceof iQuery.prototype.init;  //true

这里调用 iQuery() 是创建了init的一个对象。

//代码5 多了//2

var iQuery=function (){
    name="iQuery";   //4
    return new iQuery.prototype.init();   //1
};
iQuery.prototype={
    init : function(){
        this.name="iQueryPrototypeInit";   //5
        return this;   //2
    },

    name : "iQueryPrototype"   //6
};

iQuery().name;  //结果为  iQueryPrototypeInit

分析: 执行 iQuery().name;执行流程

1 创建一个对象
2 让 this 引用这个对象
3 为 this 所引用的对象添加属性 name
4 返回 this 所引用的对象

iQuery() instanceof iQuery  //false
iQuery() instanceof iQuery.prototype  //VM125:1 Uncaught TypeError: Right-hand side of 'instanceof' is not callable(…)

iQuery.prototype 是一个对象 instanceof 右边必须是类,即函数名

iQuery() instanceof iQuery.prototype.init;  //true

这里调用 iQuery() 是创建了init的一个对象。

总结1 如果使用new创建对象加不加 return this 是一样的。

//代码6 去掉//1 处的 new //2处有 return this

var iQuery=function (){
    name="iQuery";   //4
    return iQuery.prototype.init();   //1
};
iQuery.prototype={
    init : function(){
        this.name="iQueryPrototypeInit";   //5
        return this;   //2
    },

    name : "iQueryPrototype"   //6
};
iQuery().name;   // iQueryPrototypeInit

如果去掉 //5

iQuery().name;   // iQueryPrototype

分析: 执行 iQuery() 返回了 iQuery.prototype 这个由字面常量创建的对象

如果没有去掉 //5 则给 iQuery.prototype 添加了 name 属性覆盖了原有的name
在这里 iQuery.prototype.init()iQuery.prototype 这个对象调用了 init 函数
所以 initthis 指向了 iQuery.prototype

结论2: 函数中的 this 始终指向直接调用它的对象 ,注意是直接,为什么说是直接 请看 //代码6

//代码7

var iQuery=function (){
    name="iQuery";   //4
    return iQuery.prototype.init();   //1
};
iQuery.prototype={
    init : function(){
        return this;   //2
    },

    name : "iQueryPrototype"   //6
};

var temp ={};
temp.name="temp";
temp.sayName=iQuery().init;  // 等价于 temp.sayName=iQuery.prototype.init;
temp.name;   // 结果  temp
temp.sayName.name;   // 结果  temp

分析: 执行 temp.sayName=iQuery().init; 为对象 temp 添加了一个 sayName 方法,sayName 引用了 iQuery().init/temp.sayName=iQuery.prototype.init这时 init 中的 return this 这个 this 指向 temp 因为是 temp 直接调用 init

总结:JavaScript中的 this 是上下文 这个上下文特指是函数的上下文,就是函数所属的对象JavaScript中的 bind,call,apply 方法都能切换 函数的上下文,这和代码 //6 的原理相同都是改变 this 的指向,所以叫做上下文切换

//代码8 (本文最重要的点) 对象和类之间的关系(instanceof)

var iQuery=function (){
    name="iQuery";   //4
    return new iQuery.prototype.init();   //1
};
iQuery.prototype={
    init : function(){
    },

    name : "iQueryPrototype"   //6
};

iQuery.prototype.init.prototype=iQuery.prototype;   //3

// 注意 增加了 //3
这时执行:

a: iQuery() instanceof iQuery().init; //true
b: iQuery() instanceof iQuery; //true;

如果去掉 //3
c: iQuery() instanceof iQuery; //false;

分析: 我调用 iQuery() 创建的明明是 构造器 init 的对象啊 a:的结果才是符合逻辑的结果,b: 是什么鬼啊,和他有毛关系啊

  请看  //代码9  //代码10

//代码9

var pro={};
var A=function(){};
A.prototype=pro;
var B=function(){};
B.prototype=pro;
var a=new A();
var b=new B();
执行:
a instanceof A;   //true
a instanceof B;   //true
b instanceof A;   //true
b instanceof B;   //true

//代码10

var pro={};
var A=function(){};
A.prototype=pro;
var B=function(){};
B.prototype=pro;
var a=new A();
var b=new B();
var C=function(){};
C.prototype=a;
var c=new C();

c instanceof A;   //true
c instanceof B;   //true
c instanceof C;   //true

分析: 看到这里大家一定会明白Jquery的设计者为什么加 iQuery.prototype.init.prototype=iQuery.prototype;

虽然源码中用了 fn 但是 fn 就是 Jquery.prototype我给出我的结论

结论3: JavaScript 中的对象和类(即 构造器) 之间除了 对象的_proto_ 属性指向了 类(构造器)指定的 prototype之外,对象和类之间没有更多的关系。类型完全由 prototype 决定。具有相同 prototype 的所有构造器的对象都具有相同的类型

最后: Jquery中的init中有 return this 对于使用 new 函数名() 这样的方式创建对象有无 return this 是一样的。那Jquery为什么加啊,因为Jquery中的很多其它方法可以进行链式调用,这些方法中通过 return this 返回由init创建的对象,为了保持一致 所以init中的 return this 真的可以去掉。对于使用 new 函数名() 创建 对象 return this 和无返回值一样因为默认就会返回 thisreturn 基本类型,则 return 会被忽略依然 return this。 如果 return 引用类型 那么返回结果就是 引用类型的对象。

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
4年前
eclipse中不能找到dubbo.xsd解决方法
使用dubbo时遇到问题:org.xml.sax.SAXParseException: schema\_reference.4: Failed to read schema document 'http://code.alibabatech.com/schema/dubbo/dubbo.xsd', because 1) could not f
Wesley13 Wesley13
4年前
java通过sina端口提取股票历史数据并存入MySQL
 1.提取股票代码代码见:http://www.oschina.net/code/snippet\_2688840\_55337(http://www.oschina.net/code/snippet_2688840_55337) 2抓取sina股票的json页面数据;代码见:http://www.oschina.net/code/snip
虾米大王 虾米大王
3年前
java代码092
code092.jsp通过FindServlet类查询分页数据所有图书信息ID图书名称价格数量作者<%Listlist1(List)request.getAttribute("list");for(code089book:list1)%
虾米大王 虾米大王
3年前
java代码034
code034.jspPage对象各方法的应用getClass():hashCode:toString():与object对象比较:与this对象比较:
虾米大王 虾米大王
3年前
java代码012
code012.jspInserttitlehere<%JSP内置对象1.request用于处理HTTP请求中的各项参数。如,删除可以通过request对象的getParameter()方法获取如,request.getParameter("id")在请求转发时,需要把一些数据传递到转发后的页面处理。就需要用到request的se
虾米大王 虾米大王
3年前
java代码035
code035.jsp使用exception对象获取异常信息
虾米大王 虾米大王
3年前
java代码013
code013.jsprequest对象获取请求参数处理页
虾米大王 虾米大王
3年前
java代码019
code019.jsp中文乱码问题functionlinkClick(linkObject)varformObjectdocument.createElement('form');document.body.appendChild(formObject);formObject.setAttribute('method',
Wesley13 Wesley13
4年前
PHP 调用qq邮箱接口
html代码<!DOCTYPEhtml<html<head<metacharset"UTF8"<title</title<scriptsrc"https://code.jquery.com/jquery1.9.1.min.js"</script
Stella981 Stella981
4年前
JQuery中对option的添加、删除、取值
jQuery获取Select选择的Text和Value:1\.$("select\_id").change(function(){//code...});  //为Select添加事件,当选择其中一项时触发2\.varcheckText$("select\_id").find("option:selected").text();  
Stella981 Stella981
4年前
PowerDesigner列名、注释内容互换
在用PowerDesigner时,常常在NAME或Comment中写中文在Code中写英文,Name只会显示给我们看,Code会使用在代码中,但Comment中的文字会保存到数据库TABLE的Description中,有时候我们写好了Name再写一次Comment很麻烦,以下两段代码就可以解决这个问题。在PowerDesigner中PowerDesig