引言:在 javascript王国的一次旅行,一个没有类的世界怎么玩转面向对象? 一文中我们提到了在没有类概念的 JavaScript 语言中是通过原型来实现面向对象的继承特性。只要运用得好,这种基于原型的 JavaScript 继承模型比传统的类继承还要强大。所以我们还需详细学习一下原型的知识
JavaScript 的对象
JavaScript 是基于对象的面向对象语言。因此在这里的“对象”既可以是普通对象(Object),也可以是函数对象(Function)。JS 抛弃了 Java 的类概念,而 Java 的继承恰恰是通过类来实现的。那么 JS 没有类的概念,就使用了“原型”的概念来实现继承。
字面量原型及原型链
JS 可通过字面量构造对象。为了实现继承,对象里面有个_proto_
属性可以指向该对象的父对象。这个父对象就是所谓的“原型”。
var animal = {
name: '动物',
eat: function(){
console.log(this.name + " is eating");
}
};
animal.eat(); // animal is eating
var dog = {
name: '狗',
_proto_: animal
};
var cat = {
name: '猫',
_proto_: animal
};
dog.eat(); // 狗 is eating
cat.eat(); // 猫 is eating
由上面代码我们可以看出:dog 和 cat 对象的原型都是 animal。但是 dog 和 cat 对象都没有定义 eat()
方法,那怎么可以调用呢?其实当eat方法被调用的时候,先在自己的方法列表中寻找, 如果找不到,就去找原型中的方法, 如果原型中找不到, 就去原型的原型中去寻找...... 最后找到Object那里, 如果还找不到, 那就是未定义了。这几个对象通过_proto_
属性建立一个原型链!
由上面的代码和示意图可看出这个所谓的构造函数 Student 其实就是一个幌子啊, 每次去new Student
的时候,确实会创建一个对象出来( andy 或者 lisa ) , 并且把这个对象的原型指针(_proto_)指向 Student.prototype 这个对象,这样一来就能找到sayHello()
方法了。我们应该还知道上面的构造函数Student()
对象(JS 中函数也是对象)会创建一个 prototype 对象(Student.prototype),而 new 出来的实例对象例如 andy 和 lisa 是没有这个 prototype 对象,但是他会有个 proto 属性(_proto_)指向这个构造函数对象的 prototype 对象,从而构成原型链。实例对象其实是通过原型对象与构造函数取得联系的。为了让 Java、C#、C++ 程序员降低学习成本,JavaScript 提供了语法糖:
class Student {
constructor(name){
this.name = name;
}
sayHello(){
console.log("Hi, I'm "+this.name);
}
}
var andy = new Student("andy");
andy.sayHello(); //Hi, I'm andy
Object.create()
var a = Object.create(null);
console.log(a); //{}
a.name = 'Zhiyu';
var b = Object.create(a);
console.log(b); //{}
console.log(b.name); //Zhiyu
上面我们可以看出该方法是创建一个空对象,空对象的原型是create()
参数。此时创建的空对象会有个(_proto_)属性指向方法参数,这样也可以构成一个原型链。
总结
- JS 在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做 _ proto_ 的内置属性,用于指向创建它的函数对象的原型对象 prototype
- 原型和原型链是 JS 实现继承的一种模型
- 原型链是靠 _proto _ 形成的,而不是 prototype
- 所有的原型对象都有 constructor 属性,该属性对应创建所有指向该原型的实例构造函数
- 函数对象和原型对象通过 prototype 和 constructor 属性进行相互关联
参考
最后是广告时间,我的原创博文将同步更新在三大平台上,欢迎大家点击阅读!谢谢
稀土掘金
网友评论