资讯专栏INFORMATION COLUMN

原型(prototype)相关方法,jquery类型判断源码分析。

madthumb / 907人阅读

摘要:先来看一个这样的对象在函数的原型上扩展了一个方法可以看到实例化的对象下有一个属性,而这个属性就指向构造函数的原型对象。重点是,连接的是实例对象与构造函数原型对象,而不是,实例对象和构造函数。

前言

介绍原型的概念,和相关属性,以及jquery判断纯净对象的实现,不小心点进来的直接 ctrl+f 搜你想找的属性。

什么是原型

isPrototypeOf() || Object.getPrototypeOf()

hasOwnProperty() || in

jQuery.isPlainObject() 源码解读

什么是原型

prototype(原型,雏形,蓝本) 说新上市的一部手机的原型机,就可以用这个单词。
每一个函数默认都有一个prototype(原型)属性,这个属性指向函数的原型对象。就是说函数的原型是一个对象。先来打印一个函数的这个prototype属性,来看看他是什么样的。

function Zoom(){};
var proto = Zoom.prototype;
console.log(proto);

眼见为实,这就是Zoom函数的原型对象,其中还有一个constructor 属性,我们并未对prototype原型对象进行修改,但却有一个constructor属性。默认情况下,函数的原型对象都会获取到一个constructor属性。
constructor(构造器)英文中的解释为构造器。图中constructor的属性值为Zoom函数。便于记忆,也可以理解为,函数的原型是由函数产生的,那构造出原型的东西,就是函数本身。也就是:

Zoom.prototype.constructor = Zoom;
//语言描述就是:zoom函数的原型对象的constructor属性,指向函数本身。

当我们通过new操作符,获取了一个构造函数的实例后(就是产生了一个对象)。先来看一个这样的对象:

function Zoom(){
  this.bird = function(){
    console.log("bird");
  }
};
//在函数的原型上扩展了一个方法
Zoom.prototype.cat = function(){
  console.log("cat");
}
var zoom = new Zoom();
console.log(zoom);

可以看到实例化的zoom对象下有一个__proto__属性,而这个属性就指向构造函数Zoom的原型对象。重点是,__proto__连接的是实例对象与构造函数原型对象,而不是,实例对象和构造函数。

isPrototypeOf() || getPrototypeOf()
function Zoom(){
  this.bird = function(){
    console.log("bird");
  }
};
//在函数的原型上扩展了一个方法
Zoom.prototype.cat = function(){
  console.log("cat");
}
Zoom.prototype.fish= function(){
  console.log("fish");
}
var zoom1 = new Zoom();
var zoom2 = new Zoom();
zoom1.cat ();//cat
zoom2.fish();//fish
console.log(zoom1);
console.log(zoom2);

根据上一节说的,zoom1,zoom2实例对象都有一个属性__proto__指向构造函数的原型对象,换句话说,就是实例对象和构造函数没什么直接的联系。
但是我们发现,这两个实例都不包含方法,却能够使用a,b 方法,这就是通过查找对象属性的过程来实现的。
当我们在调用一个对象的属性值是,首先会从实例对象本身开始搜索,如果找到了就返回属性值,没有找到就在原型对象上查找。这也是原型对象的属性或方法可以共享的原因。
那如何知道一个对象,例如两个实例的原型链中,是否有构造函数的原型对象(Zoom)的方法呢。这就是isPrototypeOf()。用来确定一个对象是否存在于另一个对象的原型链中。

console.log(Zoom.prototype.isPrototypeOf(zoom1));//true

虽然原型可以共享,但是不能通过实例对象修改原型:

zom1.cat = function (){
  console.log("zom1 输出的 cat");
}
zom1.cat ();//z1 输出的 cat
zom2.cat ();//原型输出的cat

这个其实很好理解,因为对象属性查找是从实例向原型上查找,所以写在实例上的方法如果和原型上的方法同名的话,会屏蔽原型上的方法,可以简单理解为就近原则。

hasOwnProperty() || in

既然同一个方法可以出现在实例中,也可以出现在原型中,如何可以判断是否在实例中呢。
hasOwnProperty() 方法会返回一个布尔值,指示对象是否具有指定的属性作为自身(不继承)属性。
如果判断在zoom1对象自身是否有a属性,就可以:

zoom1.hasOwnProperty(bird); // true
zoom1.hasOwnProperty(fish); // false

因为bird 是zoom1 自身的属性,所以返回true,而fish是zoom1原型的的属性,所以返回false。
另一个要介绍的in方法,它比hasOwnProperty判断的范围更大,无论在原型上或者是在实例上,如果存在要检测的属性,都会返回true。

"bird" in zoom1; // true
"fish" in zoom1; // false

那就可以理解为,在in方法的判断范围中中排除hasOwnProperty的判断范围,剩下的不就是属性只出现在原型中的可能。
转为简单逻辑就是,如果in为真则可能在实例中也可能在原型中,如果hasOwnProperty方法为假,就肯定不是在实例中。所以in为真,hasOwnProperty为假,就一定是在原型中:

function hasProtoTypeProto(attr,obj){
   return !obj.hasOwnProperty(attr) && (attr in obj)
}
hasProtoTypeProto("fish",zoom1) //true
hasProtoTypeProto("bird",zoom1) //false
isPlainObject()

是jquery提供的外部可以直接使用的方法,这个方法是用来判断一个对象是否是纯粹的对象,即对象字面量,而不是一个构造函数的实例。其中涵盖了大部分原型相关的方法。我们先来看一下如何使用。

var log = console.log.bind(console);
log(jQuery.isPlainObject({x:0}));//true
log(jQuery.isPlainObject(new Object({})))//true
log(jQuery.isPlainObject([0]))//false
function Zoom(){
  this.fish = function(){
    return "Im a fish";
  }
}
var zoom = new Zoom();
log(jQuery.isPlainObject(zoom))//false

可以看到只有纯粹的对象才会返回真,typeof类型检测出数组为object,或是构造函数的实例都是返回假。我们看一看在jquery 3.1版本中是如何实现这个方法的。分析过程请见代码:

//传入需要判断的对象
function isPlainObject(obj) {
//没有具体的意义只是保存其他执行的结果。
var proto, Ctor;
if (!obj || toString.call(obj) !== "[object Object]") {
  // toString 在之前的代码中已被定义为 Object.prototype.toString,代码等价于Object.prototype.toString.call( obj ) !== "[object Object]"
  //在任何值上调用Object 原生的toString()方法,都会返回一个[object NativeConstructorName] 格式的字符串,
  //[[Class]]是一个内部属性,所有的对象(原生对象和宿主对象)都拥有该属性,这个属性中就指定了上述字符串中的构造函数名(NativeConstructorName)
  // 类似的 [object Array] [object Function] [object RegExp]
  //但是这个判断不能排除一个实例对象,因为上[[Class]] 属性默认保存对象的类型,所以也会返回Object;
  //所以除了对象的其他类型,都会返回false
  return false;
}
proto = getProto(obj);
// getProto 之前已经被定义为 getProto = Object.getPrototypeOf 返回对象构造函数的原型
// Objects with no prototype (e.g., `Object.create( null )`) are plain
// 上一行是坐着的注释,即为通过Object.create( null ) 方法,可以创建一个没有原型的对象null
// 所以如果proto 为false,表示对象没有原型,只会是null,而null也是一个纯粹的对象,所以返回真
if (!proto) {
  return true;
}

Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
// Objects with prototype are plain iff they were constructed by a global Object function
// hasOwn之前被定义为,hasOwn = {}.hasOwnProperty 
// hasOwn.call( proto, "constructor" ) 传入对象构造函数的原型,判断原型上面有没有constructor属性(而不是在原型链的其他位置),因为constructor属性只会出现在Object函数的原型上,其他函数原型的constructor属性,都是从Object原型上继承来的
// 所以有constructor属性表示是通过Object对象得到的,但是还不能确定为是Object的实例,或是字面量方式得到。最后保存proto.constructor 即是传入对象的构造函数


return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
// fnToString被定义为hasOwn.toString 即是{}.hasOwnProperty.toString.call(Ctor);
// ObjectFunctionString定义为fnToString.call( Object ) 即是{}.hasOwnProperty.toString.call(Object);
// 所以 typeof Ctor = "fuction" 为函数就是需要判断对象的原型是函数类型,{}.hasOwnProperty目的是得到一个函数,一个函数的toString方法会以字符串的格式显示函数
// 如果两个字符串相等,表示两个函数相等。也就表示传入对象的构造函数就是Object,所以他是一个纯净的对象。

}

至此就是全文的所有内容,有疑问尽情留言,一定回复。

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

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

相关文章

  • jQuery核心源码学习设计思想和JS特性

    摘要:原型数据类型检测指向绑定执行环境深拷贝三源码分析匿名自执行函数和闭合包这里形成闭包保护变量不被直接访问和篡改保证框架完整性,闭包的作用域内也会帮助缓存变量值。 一、导读 文章作为学习笔记的形式,记录学习的一点体会和原理知识,如有错误欢迎指正。 本文根据一些简单的jQuery源码入手分析一个框架从哪方面入手,js在底层做了那些事, 了解他的设计思想,jquery整体架构还是依托于js,在...

    LucasTwilight 评论0 收藏0
  • 浅析jQuery整体框架与实现(上)

    摘要:通常的做法是,为它们指定回调函数。请求返回请求返回请求返回异步队列解耦异步任务和回调函数为模块队列模块事件提供基础功能。 前言 jQuery整体框架甚是复杂,也不易读懂,这几日一直在研究这个笨重而强大的框架。jQuery的总体架构可以分为:入口模块、底层模块和功能模块。这里,我们以jquery-1.7.1为例进行分析。 jquery的总体架构 16 (function( window,...

    VEIGHTZ 评论0 收藏0
  • 听飞狐聊JavaScript设计模式系列04

    摘要:介一回,偶们来聊一下用中的类,有些盆友可能用过或者的,知道语法糖,可是在中并没有,中需要用到构造函数来模拟类。而且要注意一点,构造函数没有语句,是自动返回。 本回内容介绍 上一回聊到JS的Function类型,做了柯里化,数组去重,排序的题。 介一回,偶们来聊一下用JS中的类,有些盆友可能用过ES6或者TypeScript的,知道Class语法糖,可是在ES5中并没有,ES5中需要用到...

    kgbook 评论0 收藏0
  • jQuery中的isPlainObject()方法 实现原理

    摘要:说明中的函数用于判断指定参数是否是一个纯粹的对象,返回值为类型。使用语法参数说明任意类型需要进行判断的任意值。函数的方法会返回一个表示函数源代码的字符串。具体来说,包括关键字,形参列表,大括号,以及函数体中的内容。 说明 jQuery中的isPlainObject() 函数用于判断指定参数是否是一个纯粹的对象,返回值为Boolean类型。 纯粹的对象,就是通过 { }、new Obje...

    leon 评论0 收藏0
  • Zepto 源码分析 2 - Polyfill 设计

    摘要:此模块包含的设计思路即为预以匹配降级方案。没有默认编译该模块,以及利用该模块判断后提供平台相关逻辑的主要原因在于其设计原则的代码完成核心的功能。此处,也引出了代码实现的另一个基本原则面向功能标准,先功能覆盖再优雅降级。 在进入 Zepto Core 模块代码之前,本节简略列举 Zepto 及其他开源库中一些 Polyfill 的设计思路与实现技巧。 涉及模块:IE/IOS 3/Dete...

    chuyao 评论0 收藏0

发表评论

0条评论

madthumb

|高级讲师

TA的文章

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