从Object.prototype.toString聊到原型

栏目: JavaScript · 发布时间: 5年前

内容简介:通常在 JavaScript 里使用很明显上述得出来的结果不符合我们的要求,那么就不得不使用Object.prototype.toString方法去解决我们的技术首先我们先来介绍toString方法,这个方法就是转为字符串的方法,跟Object.prototype.toString对比如下:

通常在 JavaScript 里使用 typeof 来判断数据类型,只能区分基本类型,即 “number”,”string”,”undefined”,”boolean”,”object”,“function”,“symbol” (ES6新增)七种。 但是还是有些边界情况我们无法判断的,比如:

console.log(typeof null) // object
 console.log(typeof [1,2,3]) // object
复制代码

很明显上述得出来的结果不符合我们的要求,那么就不得不使用Object.prototype.toString方法去解决我们的技术 痛点

Object.prototype.toString实现类型检测

首先我们先来介绍toString方法,这个方法就是转为字符串的方法,跟Object.prototype.toString对比如下:

let arr=[1,2,3];

//直接对一个数组调用toString()
 console.log(arr.toString()) // "1,2,3"
 console.log(Object.prototype.toString()) //[object Object]
复制代码

你会发现Object.prototype.toString方法返回的结果有我们需要的,你可以通过 Object.prototype.toString()=="[object Object]" 来判断是不是object类型,那么有同学就说我要检测的是 Array 类型呢,是这样写吗:

console.log(Array.prototype.toString()) 
复制代码

结果是打印出来的为 空的 ,为什么会这样这样子呢,Object.prototype中的toString方法是确实被继承下来了,但是数组重写了toString方法,所以直接调用数组对象上面的toString方法调用到的实际是重写后的方法,并不是Object.prototype中的toString方法,所以要明确是只有 Object.prototype.toString方法返回的结果是"[...]" ,也就是 只有Object.prototype上的toString才能用来进行复杂数据类型的判断 ,而其他类型可能内部有他们自己的写法,那我们如果想要判断其他类型如何调用这个方法呢,聪明的同学可能想到去 改变Object.prototype.toString上下文的执行环境 ,那么自然而然想到call方法(apply方法):

let arr=[1,2,3];
 console.log(arr.toString()) // "1,2,3"
// 通过call指定arr数组为Object.prototype对象中的toString方法的上下文
 console.log(Object.prototype.toString.call(arr)) // "[object Array]"
复制代码

那么我们的问题就解决了,很精确判断出类型,实际上我们是通过Object.prototype的原型方法去实现的,那么这里就不得不聊下 原型以及原型链方面的知识了

深入了解原型及原型链

在面试题或者开发中经常会遇到prototype,_proto,constructor等一系列名词,比如:

从Object.prototype.toString聊到原型

打印的这个对象里面有__proto__属性,属性下包含着constructor属性和__proto__属性等,看起来很复杂那今天我们就好好剖析这个知识点吧!!!

构造函数和原型的关系

prototype(翻译为原型):每个 函数 都有一个 prototype 属性,那么构造函数和prototype是怎么样的一种指向关系

举个例子:

function Animal() {

}
// prototype是函数才会有的属性
Animal.prototype.name = '旺财'
let animal1 = new Animal()
let animal2 = new Animal()
console.log(animal1.name) // 旺财
console.log(animal2.name) // 旺财
复制代码

这里有个问题:我们Animal没有声明name字段,为什么我们的实例化对象animal1和animal2会具有name字段?还有构造函数跟原型之间又有什么关系?

其实,函数的 prototype属性指向了一个对象 ,这个对象正是调用该构造函数而创建的实例的原型,当我们进行new操作( new操作下面会重点讲到 )的时候返回的animal1对象字段相当于由Animal和Animal.prototype实例原型组成,你可以看到 toString方法 ,但是我们Animal构造函数并没有声明这个方法这是 继承 于Animal.prototype原型对象,name字段也是,其 构造函数和原型的关系 图如下:

从Object.prototype.toString聊到原型

这里我们有必要弄清楚一些叫法,因为概念有点多容易混淆

  • 只有(构造)函数才具有prototype属性
  • prototype是属性不是原型,通过该属性才能找到原型
  • Animal.prototype才是我们所说的原型,也叫实例原型

如何通过实例化对象指向实例原型(proto)

每一个JavaScript对象(除了 null )都具有的一个属性,叫__proto__,这个属性会指向该对象的原型

举个例子:

function Animal() {

}
let animal = new Animal()
console.log(animal.__proto__ === Animal.prototype) // true
复制代码

于是构造函数、实例原型和__proto__属性之间的关系图如下:

从Object.prototype.toString聊到原型

我们上述讲到的都是指向实例原型,那么我们可不可以通过原型指向构造函数,答案肯定是可以的

constructor指向构造函数

有同学会说实例原型可以指向实例化对象,那是不行的因为我们new很多个实例对象,但是要通过constructor指向实例化对象是不能的,那么我们就来看看constructor如何指向构造函数 走下代码:

function Animal() {

}
let animal = new Animal()
console.log(animal)
console.log(Animal === Animal.prototype.constructor) // true
console.log(animal.__proto__.constructor=== Animal) // true
复制代码

那么我们可以更新下关系图:

从Object.prototype.toString聊到原型
以上效果图也就是我们常说的原型链

,好了理解清楚原型和原型链这些知识点,我么来看看上面所要介绍的new操作符


以上所述就是小编给大家介绍的《从Object.prototype.toString聊到原型》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入理解Java虚拟机

深入理解Java虚拟机

周志明 / 机械工业出版社 / 2011-6 / 69.00元

《深入理解Java虚拟机:JVM高级特性与最佳实践》内容简介:作为一位Java程序员,你是否也曾经想深入理解Java虚拟机,但是却被它的复杂和深奥拒之门外?没关系,本书极尽化繁为简之妙,能带领你在轻松中领略Java虚拟机的奥秘。本书是近年来国内出版的唯一一本与Java虚拟机相关的专著,也是唯一一本同时从核心理论和实际运用这两个角度去探讨Java虚拟机的著作,不仅理论分析得透彻,而且书中包含的典型案......一起来看看 《深入理解Java虚拟机》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具