资讯专栏INFORMATION COLUMN

由Jquery创建对象引发的思考

Harpsichord1207 / 219人阅读

摘要:具有相同的所有构造器的对象都具有相同的类型最后中的中有对于使用函数名这样的方式创建对象有无是一样的。对于使用函数名创建对象和无返回值一样因为默认就会返回。

读到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 引用类型 那么返回结果就是 引用类型的对象。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80326.html

相关文章

  • 一个“bug”到鲜为人知jQuery.cssHooks

    摘要:干想了半天,认为可能还是本身的写法问题。对象提供了一种通过定义函数来获取或设置特定值的方法。简单来说,给我们暴露了一个钩子,我们可以自己定义方法比如,来实现针对某个属性的特定行为。 写在最前 本次分享一下在一次jQuery赋值样式失效的结果中来分析背后原因的过程。在翻jQuery源码的过程中,感觉真是还不能说自己只是会用jQuery,我好像连会用都达不到(逃 欢迎关注我的博客,不定期更...

    ernest.wang 评论0 收藏0
  • 一个“bug”到鲜为人知jQuery.cssHooks

    摘要:干想了半天,认为可能还是本身的写法问题。对象提供了一种通过定义函数来获取或设置特定值的方法。简单来说,给我们暴露了一个钩子,我们可以自己定义方法比如,来实现针对某个属性的特定行为。 写在最前 本次分享一下在一次jQuery赋值样式失效的结果中来分析背后原因的过程。在翻jQuery源码的过程中,感觉真是还不能说自己只是会用jQuery,我好像连会用都达不到(逃 欢迎关注我的博客,不定期更...

    malakashi 评论0 收藏0
  • 「Metaspace容量不足触发CMS GC」从而引发思考

    摘要:第一个大陡坡是应用发布,老年代内存占比下降,很正常。但此时老年代内存使用占比。因为后期并不会引发。可以看出,由于到达时候,触发了一次和一次。但触发时,占比并没用明显的规律。得出,扩容导致这个说法,其实是不准确的。 转载请注明原文链接:https://www.jianshu.com/p/468... 某天早上,毛老师在群里问「cat 上怎么看 gc」。 showImg(https://...

    StonePanda 评论0 收藏0
  • 一道面试题引发思考 --- 理解 new 运算符

    摘要:首先,我先去上搜索了的定义运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。 今天看到一道面试题,如下,问: 实例化 Person 过程中,Person返回什么(或者 p 等于什么)? function Person(name) { this.name = name return name; } let p = new Person(Tom); 说实...

    shengguo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<