[[Prototype]]:原型
在聊原型大家族之前,我们需要了解一下其中的重要成员[[Prototype]].在JavaScript中,每一个对象有一个特殊的[[Prototype]]内置属性,实际上这是对于其他对象的引用。几乎所有的对象在创建[[Prototype]]时都会被赋予一个非空的值。实际上,[[Prototype]]也是一个对象,里面也具有属性和方法。
在JavaScript中,我们这样定义: 原型是函数function对象的一个属性,它定义了构造函数制造出来的对象的公共祖先 通过构造函数产生的对象,可以继承到原型的方法和属性。
看到这里,是不是会想到类的继承?确实,二者有异曲同工之妙,但是class类的继承需要使用关键字extends和super关键字来实现,而原型是一个对象,它是对象的引用,自身也是一个对象,二者要区分开。
共有属性
利用原型的特点和概念,我们可以提取共有的属性
Person.prototype.say = function(){
console.log('hello');
}
function Person(){
this.name = '小明'
}
var person = new Person()
var person1 = new Person()
console.log(Person.name);//小明
console.log(person1.name);//小明
//它定义了构造函数制造出来的对象的公共祖先 方法say()
person.say()
person2.say()
定义一个构造函数Person,name属性赋值为‘小明’,在其原型对象上添加方法say(),则只要是Person定义出来的对象,都会具有say这个方法,并通过对象.say()的方式来调用
增添删改
我们不仅可以对对象进行增添删改,还能对原型对象进行增添删改
Person.prototype.lastName = '王'
function Person(name){
this.name = name
}
person.lastName = '李'; //相当于给Person类创建的对象person加了一个属性
console.log(person.lastName); //李
console.log(Person.prototype.lastName); //王
Person.prototype.lastName = '李' //原型得到修改
console.log(Person.prototype.lastName); //李
delete person.lastName //删除person对象的属性
console.log(person.lastName); //李
delete Person.prototype.lastName //删除原型属性
console.log(Person.prototype.lastName);//undefined
上述代码我们定义了一个构造函数,定义属性name,需要传入参数。同时我们在对象的原型对象上也增添一个属性lastName,将其赋值为‘王’。我们定义一个对象person,为person对象增添一个属性lastName,注意,这里相当于是给Person类创建的对象person加了一个属性,而后打印属性lastName,很显然是 ‘李’。之后修改原型上的lastName的值为 ‘李’,打印结果便是 ‘李’。然后删除了person对象的属性,但是打印结果仍然是 ‘李’,这是为何呢?结果在下方揭晓,这里留个悬念。最后删除原型的属性,打印结果很显然为undefined。
显式原型
每个对象都有隐式原型,就是__proto__
隐式原型
每个对象也具有显式原型,就是prototype
Person.prototype.name = '王'
function Person(){
}
var Person = new Person()
console.log(Person);//{} 是由Person{}创建的
console.log(Person.__proto__);
console.log(Person.__proto__.name);
var obj = {
name:'李'
}
Person.__proto__ = obj
console.log(Person.__proto__); //
console.log(Person.__proto__.name);//wn 前往obj去寻找
可以看到,全局中定义了一个Person构造函数,构造出Person对象,打印Person.__ proto__,我们发现它就是一个对象,其中就包含了name,以及它自身的构造函数,里面同样包含了prototype属性。而利用__proto__属性,可以改变对象的引用,让其指向新的对象obj,从而前往obj去寻找lastname,输出相应的值。
值得注意的是,构造函数的显式原型是个对象,对象的隐式原型Person.__ proto__ 也是一个对象
构造函数 与 对象
从上面的例子中,我们就容易看出原型prototype和__proto__存在着某种莫大的联系:对象的隐式原型等于构造函数的显式原型.用代码来说,就是person.__ proto__ == Person.prototype
Person.prototype.say = function(){
console.log('aaaaa');
}
function Person(name){
this.name = name
return this
}
let p = new Person('袁')
p.say( )
为什么p可以拿到say ()这个方法呢?实际上在构造函数创建对象是,构造函数对对象内部做了以下操作
var this = {
name: name
__proto__:Person.prototype
}
return this
构造函数三部曲
1 创建this对象
2 挂上对象该有的属性值,name属性传值,对象的隐式原型绑定构造函数显示原型
3 返回this对象
原型链
在这里,我们又要引出一个概念,原型链:在原型上加一个原型,再加一个原型,把原型连成链,访问顺序按照链的顺序执行,叫原型链.
所有对象都有自己的原型对象,而原型对象也是对象,所以它也有自己的原型,原型同样也具有原型对象,依次嵌套,形成了一个原型链,也就是说,对象最终都会回溯到Object.prototype上 ,而Object.prototype的原型 对象就是null
从上述代码中来说,如果自身没有该属性,那么JavaScript就会去原型对象中找,若是有,则将其赋值,否则,就要去原型的原型对象中,又是这样一种嵌套,一直沿着原型链,最终回溯到Object.prototype上,若是仍然没有,那么结果就是undefined。
小白的见解,希望可以帮到大家,谢谢!