对象及原型链
本文仅为前端初学者整理知识点,不做他用。
面向对象的三大特性
- 封装
- 继承
- 多态
原型链
原型链是面向对象的基础,主要从以下几方面入手:
- 创建对象的几种方法
- 原型、构造函数、实例、原型链
- instanceof的原理
- new运算符
创建对象的方法
- 字面量
var obj11 = {name:“莉莉”};
var obj12 = new Object(name:“莉莉”);//内置对象的构造函数
以上两种写法得到的结果一样,第一种是字面量方式,第二种是内置的构造函数。
- 通过构造函数
var Person = function(name){
this.name = name;
}
var obj2 = new Person(‘莉莉’);
- Object.create
var person = {name:‘莉莉’};
var obj3 = Object.create(person);
在这种方式里,obj3是实例,person是obj3的原型,name是person原型里的属性,Object是构造函数。
- var a = {} 其实是 var a = new Object()的语法糖;
- var a = [] 是 var a = new Array()的语法糖;
- function Foo(){…}其实是var Foo = new Function(…);
- 使用instanceof可以判断一个函数是否是一个变量的构造函数;
原型、构造函数、实例、原型链
任何一个函数,如果在前面加了new,那它就是构造函数。
原型、构造函数、实例三者之间的关系
- 构造函数通过new生成实例
- 构造函数也是函数,它的prototype指向原型。(所有函数都有prototype属性,但实例没有prototype属性)
- 原型对象有constructor,指向该原型的构造函数。
举个例子:
var Foo = function(name){
this.name=name;
}
var foo = new Foo(‘莉莉’);
4. 实例的__proto__指向原型。(proto前后各有两个横线,捂脸)
所有引用类型(对象、数组、函数)都有__proto__这个属性。例如,Foo这个函数的原型是Function构造函数的实例。
原型链
基本原理
任何一个实例都可以通过原型链找到它上面的原型,该原型对象的方法和属性可以被它的所有原型实例共享。
Object是原型链的顶端。
原型可以起到很好的继承作用。原型对象中的方法和属性可以被不同实例共享。
//给Foo的原型添加say函数
Foo.prototype.say = function(){
console.log(“你好!”)
}
原型链的关键
在访问一个实例时,如果实例本身没找到该方法或属性,就往原型上找。如果还找不到,就往上一级的原型找。
instanceof的原理
作用:用于判断实例属于哪个构造函数。
原理:判断实例的__proto__属性和构造函数的prototype属性是否指向同一个地址,是否为同一个引用。
注意:
- 实例是由构造函数new出来的,但是实例的__proto__指向的是构造函数的prototype。也就是说,实例的__proto__属性与构造函数本身无关。
- 在原型链上,原型的上面还会有原型。以此类推往上继续找__proto__属性,如果这条链上能找到,那么instanceof返回的结果也是true。
举个例子:
- foo instance of Foo的结果为true,因为foo.proto === Foo.prototype为true。
- foo instance of Object的结果为true,因为Foo.prototype.proto === Object.prototype为true。
但是我们不能说,foo是由Object创建的实例,这句话是错的。我们可以借助一个问题来思考这句话的错误。
问题:已知A继承B,B继承C,那么a是A直接生成的实例,还是由B或C生成的呢?
这需要用到原型的constructor属性,foo.proto.constructor === Foo =true,但是foo.proto.constructor === Object =false。
所以用constructor判断比instanceof要严谨。
new运算符
当new Foo()时发生了什么:
- 创建一个新的空对象实例。
- 将此对象的隐式原型指向其构造函数的显式原型。
- 执行构造函数(传入相应参数,没有不用传),同时this指向这个新实例。
- 如果返回值是一个新对象,直接返回即可;没有返回值或返回非对象值,那么返回第一步创建的对象。