从Object.prototype.toString聊到原型

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

内容简介:通常在 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聊到原型》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

复杂网络理论及其应用

复杂网络理论及其应用

汪小帆、李翔、陈关荣 / 清华大学出版社 / 2006 / 45.00元

国内首部复杂网络专著 【图书目录】 第1章 引论 1.1 引言 1.2 复杂网络研究简史 1.3 基本概念 1.4 本书内容简介 参考文献 第2章 网络拓扑基本模型及其性质 2.1 引言 2.2 规则网络 2.3 随机图 2.4 小世界网络模型 2.5 无标度网络模型 ......一起来看看 《复杂网络理论及其应用》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具