从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等一系列名词,比如:
打印的这个对象里面有__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字段也是,其 构造函数和原型的关系 图如下:
这里我们有必要弄清楚一些叫法,因为概念有点多容易混淆
- 只有(构造)函数才具有prototype属性
- prototype是属性不是原型,通过该属性才能找到原型
- Animal.prototype才是我们所说的原型,也叫实例原型
如何通过实例化对象指向实例原型(proto)
每一个JavaScript对象(除了 null )都具有的一个属性,叫__proto__,这个属性会指向该对象的原型
举个例子:
function Animal() { } let animal = new Animal() console.log(animal.__proto__ === Animal.prototype) // true 复制代码
于是构造函数、实例原型和__proto__属性之间的关系图如下:
我们上述讲到的都是指向实例原型,那么我们可不可以通过原型指向构造函数,答案肯定是可以的
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 复制代码
那么我们可以更新下关系图:
以上效果图也就是我们常说的原型链,好了理解清楚原型和原型链这些知识点,我么来看看上面所要介绍的new操作符
以上所述就是小编给大家介绍的《从Object.prototype.toString聊到原型》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。