前言: 关于原型对象的概念我在上一篇文章里已经提到了,所以,原型对象的有关知识我就不再过多的赘述了。首先来看看什么是原型链,即原型链的概念是什么
原型链介绍
- 每一个对象都有原型,原型本身又是对象,所以原型又有原型,以此类推形成一个链式结构,称为原型链。原型链的终点是
null
- 那么对象是怎么访问原型链中的成员的呢?对象访问原型链中的成员遵循的是就近原则。对象先访问自己的,自己没有就找原型的,原型没有就找原型的原型,一直到原型链终点
null
,如果还找不到。属性则获取undefined
,方法则会报错:xxx is not a function
//1.构造函数
function Person(name,age){
this.name = name
this.age = age
// this.girlFriend = ''//如果自己有girlFriend,优先访问自己的
}
//2.原型对象 : 存储具有共同特征的数据
Person.prototype.type = '哺乳动物'
Person.prototype.country = '中国'
Person.prototype.playGame = function(){
console.log(this.name + '玩游戏')
}
// 实例对象
let p1 = new Person('小熊',18)
let p2 = new Person('快跑',18)
console.log(p1)
/* 小测试 */
console.log( p1.name )//小熊 p1自己有name属性
console.log( p1.age )//18 p1自己有age
console.log( p1.type )//哺乳动物 p1自己没有type,但是p1的原型有
console.log( p1.girlFrined )//undefined p1自己没有girlFrined, p1的原型也没有girlFrined
/* 思考: p1自己没有toString, p1的原型也没有toString, 但是为什么不报错呢?
原因: p1的原型的原型有toString
*/
p1.toString()
//查看p1的原型
console.log(p1.__proto__.constractor)//Person
console.log(Person.prototype === p1.__proto__)//true
//查看p1原型的原型
console.log(p1.__proto__.__proto__.constractor)//object
console.log(object.prototype === p1.__proto__.__proto__)//true
//查看p1的原型的原型的原型
console.log(p1.__proto__.__proto__.__proto__)//null
内置对象的原型链
- 构造函数的原型本身是一个对象,只要是对象就有原型
- 所有的内置对象的原型链都是一样的,最终指向Object
- 只有对象才有原型,这里有一个地方容易搞混淆,那就是基本数据类型string、number、boolean、和基本包装类型(特殊的引用类型对象)String、Number、Boolean区分开来,不要搞混淆
Array的原型链
// 数组对象
//实例化对象
let arr = [10,20,30]//这里相当于 new Array(10,20,30)
console.log( arr )
//1.1 查看arr的原型
console.log( arr.__proto__.constructor )//Array
console.log( arr.__proto__ === Array.prototype )//true
//1.2 查看arr的原型的原型
console.log( arr.__proto__.__proto__.constructor )//Object
console.log( arr.__proto__.__proto__ === Object.prototype )//true
-
那么来思考这样一个问题,为什么arr.toString()方法和对象的toString方法得到的结果不同?
数组的toString()方法是把数组每个元素以,分割并以字符串的形式返回;对象的toString()方法返回的是特定类型[object 类型]。原因是实例对象arr的原型对象Array.prototype中有默认的toString()方法,找到原型对象Array.prototype中默认的toString()方法后就不会往上找了;而其他的实例对象的原型中没有默认的toString()方法,就会往上找,找到原型的原型,object.prototype中有toString()方法,就把这个object.prototype中toString()方法拿来用了,这两个方法虽然名字一样,但是并不一样。
Date的原型链
// 日期对象
let date = new Date()
/* js有几个特殊的对象 无法使用 log来打印的,需要用dir来打印: function date dom对象 */
console.dir(date)
//3.1 查看date的原型
console.log(date.__proto__.constructor) //Date
console.log(date.__proto__ === Date.prototype) //true
//3.2 查看date的原型的原型
console.log(date.__proto__.__proto__.constructor) //Object
console.log(date.__proto__.__proto__ === Object.prototype) //true
String对象原型链
let str = new String('abc')
console.log(str)
//2.1 查看str的原型
console.log(str.__proto__.constructor) //String
console.log(str.__proto__ === String.prototype) //true
//2.2 查看arr的原型的原型
console.log(str.__proto__.__proto__.constructor) //Object
console.log(str.__proto__.__proto__ === Object.prototype) //true
补充一个关于原型链的运算符
instanceof运算符
- 语法:
对象 instanceof 构造函数
- 作用:检测构造函数的原型prototype在不在这个对象的原型链上 举例:
let arr = [10,20,30]
// arr-> Array.prototype -> Object.prototype -> null
console.log( arr instanceof Array )//true
console.log( arr instanceof Object )//true
console.log( arr instanceof String )//false
- 应用场景:某些函数为了限制你的数据类型,在内部需要instanceof进行判断是否正确的数据类型
function fn(arr){
if( arr instanceof Array){
console.log( arr.reverse() )
}else{
console.log('数据类型错误')
}
}
fn( [10,20,30] )
fn( 'abc' )