前言
介绍 1.原型对象、原型链及其优缺点 2.原型链与作用域链的区别
一、原型对象的定义
在js中,每个对象都有一个与他关联的对象,这个对象就叫做原型对象(实例对象的__proto__ 、构造函数的prototype ),他可以使多个对象共享一个或者多个方法。
注意:__proto__ 的前后都是有两个_(下划线)的
二、构造函数、实例、原型对象的关系
function Cat(name){
this.name=name;
}
cat1=new Cat('小猫1');
cat2=new Cat('小猫2');
console.log(cat1.__proto__ == Cat.prototype)
console.log(Cat == Cat.prototype.constructor)
console.log(Cat.prototype.__proto__ == Object.prototype)
关系图
实例对象 → →
↘
构造函数 ↓ .__proto__
↓
.prototype ↓ ↑ .constructor ↓
↙
原型对象 ← ←
↓
→ → → → → → Object的原型
.__proto__
三、原型链
js在每次获取对象属性或方法时都是一次查询过程,如果在自有属性中找不到就会去原型对象中找,如果原型对象中还找不到,就会去原型对象的原型对象中找,直到找到或找至最顶端的object,这查找的路线就被叫做原型链
四、继承
实例继承原型对象的属性和方法
function Cat(name){
this.name=name;
}
cat1=new Cat('小猫1');
cat2=new Cat('小猫2');
Cat.prototype.eat=function(){
console.log(this.name+'吃')
}
cat1.eat();
cat2.eat();
五、原型继承的缺点
如果原型对象中存在引用类型的话,则所有实例都会共享,例如一个实例追加数组元素,则其他实例也会同时被追加(push)
function Animal() {}
let dog = {
name: 'origin',
type: 'shiba',
friends: ['KUN', 'Kris'],
intr: function() {
console.log(`${this.name}的朋友有:${this.friends}`);
},
}
Animal.prototype = dog;
let otherDog = new Animal();
otherDog.name = '小白';
otherDog.friends.push('小新');
otherDog.intr();
let anotherDog = new Animal();
anotherDog.name = '小智';
anotherDog.friends.push('皮卡丘');
anotherDog.intr();
otherDog.intr();
dog.intr();
六、作用域链
js里面大的范围上来说,只有两种作用域,全局作用域和函数内部作用域。 作用域的特点就是,先在自己的变量范围中查找,如果找不到,就会沿着作用域往上找。 比如我们创建了一个函数,函数里面又包含了一个函数,那么现在就有三个作用域:全局作用域、函数a作用域、函数b作用域, 此时函数b中打印出的x为3,因为执行函数b时候它在自己的范围内找到了变量x所以就不会越上继续查找,如果在函数b()中没有找到则会继续向上找,一直会找到全局变量x,这个查找的过程就叫作用域链 。
var x=1;
function a(){
var x=2;
function b(){
var x=3;
console.log(x);
}
b()
}
a();
七、作用域链和原型链的区别
作用域链是针对变量的, 查找变量时,先在自己的变量范围中查找,如果找不到就会沿着作用域往上找,直到找到或找至全局作用域,这个查找路线就是作用域链 作用域链的路线从上到下可以解读成:全局作用域==>函数1作用域==>函数2作用域
原型链的话,可以认为是针对构造函数的或者说针对构造函数对应的类的 查找对象的属性或方法时,先在自有属性中找,如果找不到就去原型对象中找,如果原型对象中还找不到的话就去原型对象的原型对象中找,直到找到或找至最顶端的Object,这查找的路线就被叫做原型链 。 原型链的路线从上到下可以解读成:Object ==> 构造函数1 ==> 构造函数2
|