一、JavaScript的原型和原型链是什么?
这是一个坑人的问题,一上来就去学JavaScript原型,那可不得了,其实你都看得懂的,但是它就是像天书一样看不懂,为什么?因为问题错了,不如首先说,为什么JavaScript中有原型的概念?JS太奇葩了,需要使用事件循环机制来处理多线程的问题,JS太奇葩了,需要使用原型机制来实现面向对象中的继承,无端端这些东西就是JavaScript其中的核心元素,因为JavaScript是函数式编程,它是使用函数来实现面向对象的元素的,多少都觉得有些混乱,它的原型对象又是个对象,不是个类模板却又可以当模板使用,Java和C++过来的多少都有点不适。
原型的意思是原生,最先的东西,是最先的模板,一个始祖,JavaScript的原型对象就是相当OOP中的父类,原型链就是所有祖先的继承连接,继承的好处是什么?当然是共用了,所有子类可以使用父类的相同属性和函数,在JavaScript中这个父类对于所有子类还是同一个父类,除了共用数据还可以节省内存。继承的特点是什么?可以直接访问所有祖先的属性或函数,在JavaScript的原型中同样有这些好处和特点。
JavaScript的原型并不是核心,继承才是核心,原型对象就是父类对象,我们需要知道的是JavaScript对象的原型对象在哪里,JavaScript如何实现多层原型对象等等。
二、JavaScript的原型是如何实现继承的?
在OOP中,类是一个模板,一般是需要根据模板才能创建一个对象实例的,在JavaScript中直接就是对象实例,每个对象都有一个proto_属性,注意不是所有浏览器都支持该属性,这里以chrome为例。proto是一个指针,它指向一个对象,这个对象就是原来对象的原型对象,所说的原型对象就是这个,如下代码:
var temp = new Object();
temp.id = 9;
console.log(temp);
输出结果为:
可以通过temp的__proto__属性访问这个原型对象,这个原型对象是一个实例对象,它也可以有自己的__proto__属性,也就是说,每个对象的__proto__属性就是这个对象的父类(原型对象),你可以看到这个__proto__自己是没有__proto__属性的,所以它是一个顶级原型对象(顶级父类),这是一个Objcet对象,实在是特别别扭,为什么?因为Object不是一个类,它是一个实例对象,怎么可以说它是一个Objcet对象,但是不妨根据构造函数constructor确定类,构造函数的名称确定了一个类,OOP中构造函数和类名也是相同的,同样是new构造函数,上面是new Object,所以temp是一个Object类型的对象,使用instanceof可以作类型判断。
其实temp的__proto__是没有名称的,这是一个数据结构实例,又没有类型,但它却是担当原型父类对象的角色,按照OOP,根据构造函数判断这是一个Object类的对象,Object同时是一个类型,又是一个函数对象,又是一个函数。。。。。。
继续看:
temp对象的原型对象__proto__的构造函数constructor下面有一个prototype属性,prototype和__proto__指向同一个原型对象,也就是说prototype和__proto__相等,temp.__proto__ == temp.__proto__.constructor.prototype为true, constructor等于Object构造函数对象。我们这里是以对象为中心,也就是试图让temp对象共享原型对象的属性或函数,仅需关注__proto__和prototype就行了(但实际上很飘忽,因为你可以在__proto__原型对象上增加公共属性和函数,也可以在Object函数对象上添加,但是普通对象temp能直接访问的是__proto__原型对象的数据)。
因为__proto__和prototype是同一个原型对象,所以我们可以给这个对象添加相应的数据实现继承,__proto__不是正式支持的属性,prototype是正式属性并可以直接使用函数对象Object访问,即:temp. __proto__ == Object.prototype,所以我们可以说一个对象的原型对象(父类对象)等于这个对象构造函数的prototype属性,Object函数对象也是一个对象,这个对象的原型对象等于这个对象的构造函数Function的prototype属性。。。。。是不是感觉有点懵?
所以我们平时开发中使用继承就用构造函数对象中的prototype即可,子类对象默认可以直接访问prototype属性中的所有内容。
三、JavaScript创建对象的方式和原型对象
一般来说JS创建对象的方式有两种,一种是new Objcet(),另一种是使用新的构造函数,其实都是一种,就是new构造函数,但是这两种是有区别的,new Objcet()产生的新对象其原型对象是Object类型的对象即Object.prototype,使用新的构造函数User产生的新对象其原型对象是User类型的对象即User.prototype,这个原型对象的原型对象是Object.prototype,再向上就没有原型对象了。
如下代码:
var temp = new Object(); // temp的原型对象为__proto__和Object.prototype
temp.id = 9;
console.log(temp.__proto__ === Object.prototype); // => true
function User(username, age){
this.username = username;
this.age = age;
}
// 等同于:user1.__proto__.email = "default@git.com";
User.prototype.email = "default@git.com";
var user1 = new User("Chrome", 17);
var user2 = new User("Safari", 9);
// 子类共用一个原型对象,这个原型对象在内存中只有一个
console.log(user1.__proto__ === user2.__proto__); // => true
console.log(user1.__proto__ === User.prototype); // => true
console.log(user2.__proto__ === User.prototype); // => true
评论前必须登录!
注册