几个要点
- 所有的引用类型(函数、数组、对象)可以自由扩展属性(null除外)
- 所有的引用类型都有一个 _ _ proto _ _ 属性(隐式,它是一个普通的对象)
- 所有的函数类型都有一个 prototype 属性(显式,它是一个普通的对象)
- 所有的引用类型,它的 _ _ proto _ _ 属性都指向它的构造函数的 prototype 属性
- 当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它的 _ _ proto _ _ 属性(即,它的构造函数的 prototype 属性)中去寻找
构造函数
构造函数模式的目的就是创建一个自定义类以及这个类的实例,实例与实例之间相互独立,即实例识别
构造函数与普通函数的区别就是构造函数首字母大写,且需要 new 关键字调用
Person 实例构造
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert("我的名字: " +this.name)
}
}
//当作构造函数使用
var person1 = new Person('Nicholas','29','Software Engineer');
person1.sayName();
//当作普通函数使用
var person2 = Person("Greg",27,"Doctor");
window.sayName();
//在另一个对象的作用域中调用
var o = new Object();
Person.call(o,"Kristen",25,"Nurse");
o.sayName();
原型
JS中,每当定义一个函数数据类型,(普通函数、类)均会自带一个 prototype 属性,这个属性指向函数的原型转换,这个属性是一个对象数据类型的值
构造函数与实例原型的关系
原型对象相当于一个公共区域,所有同一个类的实例均可访问到这个原型对象,可将对象中共有的内容,统一设置到原型对象中
原型链
_ _ proto _ _ 和 constructor
每一个对象数据类型(普通对象、实例、prototype) 都会自带一个__proro__
属性,属性值是当前实例所属类的原型(prototype
),原型对象中有一个属性,constructor
,他指向函数对象
什么是原型链
JS 中万物皆为对象,对象之间并非孤立存在,都是有关系的
对象之间的继承关系,通过 prototype
对象指向父类元素,直至指向Object
对象,这样组成的链式结构就成了原型链
以 Person 构造函数为例
person --> Person --> Object
访问对象的一个属性或方法时,先在对象自身中寻找,有则直接使用,若没有,就去原型对象中寻找,还是没有,就继续去原型对象的原型中去寻找,直至找到 Object 对象的原型,Object 对象的原型没有原型,若Object 对象的原型中还是没有找到,那么就会返回 undefined
可以使用对象的 hasOwnPrototype()
来检查对象自身中是否含有该属性,使用 in
检查对象中是否有某个属性时,如果对象中没有,而原型中有,则会返回 true
function Person(){}
Person.prototype.a = 123;
Person.prototype.sayHello = function(){
alert("Hello!");
};
var person = new Person();
console.log(person.a);//123
console.log(person.hasOwnProperty('a'));//false
console.log('a' in person);//true
person 实例中没有 a 这个属性,从 person 实例中找不到 a 属性,就会去 person 实例的原型,也就是 person.__proto__
,也就是 Person.prototype
中去查找,得到 a 的值为 123
读取实例的属性时,如果找不到,就会查找与对象关联的原型对象的属性,如果还查不到,就去找原型的原型,直至找到最顶层 Object 为止,
Object 是 JS 中所有数据类型的基类(最顶层的类),在 Object.prototype
中没有 __proto__
这个属性
console.log(Object.prototype.__proto__ === null)//true