构造函数创建对象
function Person() {
}
var person = new Person();
person.name = 'Hugh';
console.log(person.name) // Hugh
Person
就是一个构造函数(constructor
),我们使用 new
创建了一个实例对象 person
prototype
:构造函数的属性
每个函数都有一个 prototype
属性,它是函数所独有的,它是从一个函数指向一个对象(构造函数的原型对象)。
每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个原型对象,这个对象包含所有实例共享的属性和方法。
原型对象都有一个constructor
属性,这个属性指向所关联的构造函数。使用这个对象的好处就是可以让所有实例对象共享它所拥有的属性和方法。
每一个对象都会从原型”继承”属性。
function Person() {
}
// prototype是函数才会有的属性
Person.prototype.name = 'Hugh';
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // Hugh
console.log(person2.name) // Hugh
__proto__
:对象的属性
每一个JavaScript对象(除了 null )都具有的一个属性,叫 __proto__
,这个属性总是指向该对象的原型 prototype
,换句话说就是指向构造函数的原型对象(prototype
),它是对象独有的。
该属性存在于实例和构造函数的原型对象之间,而不是存在于实例与构造函数之间。
function Person() {
}
var person = new Person();
console.log(person.prototype) //undefined
console.log(person.__proto__ === Person.prototype); // true
// Object.getPrototypeOf()
//ES5的方法,可以获得对象的原型__proto__
console.log(Object.getPrototypeOf(person) === Person.prototype) // true
//isPrototypeOf()
//ES5的方法,可以通过 isPrototypeOf()方法来确定对象之间是否存在这种关系
console.log(Person.prototype.isPrototypeOf(person)) //true
判断属性是存在实例对象中,还是存在原型对象中,有以下方法
hasOwnProperty(): 可以检测一个属性是存在于实例中,还是存在于原型中。返回值为true表示该属性存在实例对象中,其他情况都为false。
in 操作符: 无论该属性存在于实例中还是原型中。只要存在对象中,都会返回true。但是可以同时使用 hasOwnProperty()方法和 in 操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中。
function Person() {}
Person.prototype.name = "HUGH";
Person.prototype.age = 29;
var person1 = new Person();
console.log(person1.hasOwnProperty("name")); //false,实例对象上没有
console.log("name" in person1); //true
person1.name = "ASURADA";
console.log(person1.name); //"ASURADA" —— 来自实例
console.log(person1.hasOwnProperty("name")); //true
console.log("name" in person1); //true
delete person1.name;
console.log(person1.name); //"HUGH" —— 来自原型
console.log(person1.hasOwnProperty("name")); //false
console.log("name" in person1); //true
constructor
每个函数都有一个原型对象,所以每个原型都有一个 constructor
属性指向创建对象的构造函数本身,实例原型指向构造函数。
function Person() {
}
console.log(Person === Person.prototype.constructor); // true
我们还可以使用 constructor
属性,所有的实例对象都可以访问 constructor
属性, constructor
属性是创建实例对象的函数的引用。我们可以使用 constructor
属性验证实例的原型类型(与 instanceof
类似)。
由于 constructor
属性仅仅是原始构造函数的引用,因此我们可以使用该属性创建新的对象,如:
function Person(){}
const person1= new Person();
const person2= new person1.constructor();
console.log(person2 instanceof Person);//true
console.log(person1 !== person2);//true
通过第一个对象实例化对象的 constructor
方法创建第2个实例化对象,说明创建的新对象 person2
是 Person
的实例,由于 person1
和 person2
不是同一个对象可以得出它们是两个截然不同的实例;
结论:
1、__proto__
是原型链查询中实际用到的,它总是指向 prototype
;
2、prototype
是函数所独有的,在定义构造函数时自动创建,它总是被 __proto__
所指。
3、所有对象都有 __proto__
属性,函数这个特殊对象除了具有 __proto__
属性,还有特有的原型属性 prototype
。 prototype
对象默认有两个属性, constructor
属性和 __proto__
属性。 prototype
属性可以给函数和对象添加可共享(继承)的方法、属性,而 __proto__
是查找某函数或对象的原型链方式。 constructor
,这个属性包含了一个指针,指回原构造函数。
实例与原型
function Person() {
}
Person.prototype.name = 'Hugh';
var person = new Person();
person.name = 'Macc';
console.log(person.name) // Macc
delete person.name;
console.log(person.name) // Hugh
原型与原型
var obj = new Object();
obj.name = 'Hugh'
console.log(obj.name) // Hugh
原型链
每个对象都有一个原型 __proto__
,这个原型还可以有它自己的原型,以此类推,形成一个原型链。当我们访问实例对象的某个属性的时候,我们先去这个对象本身的属性上去找,如果没有的话,就通过 __proto__
属性 去它的原型对象里面去,如果还是没有的话,则会在构造函数的原型的__proto__
中去找,这样一层层向上查找就会形成一个作用域链,称为原型链。
console.log(Object.prototype.__proto__ === null) // true
function Person() {}
Person.prototype.name = "HUGH"
var person = new Person();
console.log(person.name) // HUGH
console.log(person) // Person {}
console.log(person.__proto__) // {name: 'HUGH', constructor: ƒ}
console.log(person.__proto__.name) // HUGH
console.log(person.__proto__.constructor) // ƒ Person() {}
console.log(person.__proto__.constructor.prototype) // {name: 'HUGH', constructor: ƒ}
console.log(person.__proto__ === person.__proto__.constructor.prototype) // true
在原型链中的指向是,函数 → 构造函数 → Function.prototype → Object.protype → null
;
JavaScript 默认并不会复制对象的属性,JavaScript 只是在两个对象之间创建一个关联。这样,一个对象就可以通过委托访问另一个对象的属性和函数。