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


_ivenj
291 声望16 粉丝

唯大英雄能本色,是真名士自风流