原型与原型链

构造函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function Person(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.sayName = function() {
        alert(this.name);
    }
}
var per = new Person('孙悟空', 18, '男');

function Dog(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
}
var dog = new Dog('旺财', 4, '雄');
console.log(per);//当我们直接在页面中打印一个对象时,实际是输出的对象的toString()方法的返回值
// Person {
//     name: '孙悟空',
//     age: 18,
//     gender: '男',
//     sayName: [Function (anonymous)]
//   }
console.log(dog);
//Dog { name: '旺财', age: 4, gender: '雄' }

上面代码中,Person、Dog就是构造函数。为了与普通函数区别,构造函数名字的第一个字母通常大写。new命令的作用,就是执行构造函数,返回一个实例对象。per、dog就是一个实例对象。

构造函数的特点有两个:

  • 函数体内部使用了this关键字,代表了所要生成的对象实例
  • 生成对象的时候,必须使用new命令

每创建一个Person构造函数,在Person构造函数中,为每一个对象都添加了一个sayName方法,也就是说构造函数每执行一次就会创建一个新的sayName方法,这样就导致了构造函数执行一次就会创建一个新的方法,执行10000次就会创建10000个新的方法,而10000个方法都是一模一样的,为什么不把这个方法单独放到一个地方,并让所有的实例都可以访问到呢?这就需要原型(prototype)

New的实现机制

  1. 首先创建了一个新的空对象
  2. 设置原型,将对象的原型设置为函数的prototype对象
  3. 让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)
  4. 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象

原型

在JavaScript中,每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值

原型链

(1)proto和constructor

每一个对象数据类型(普通的对象、实例、prototype…..)也天生自带一个属性__proto__,属性值是当前实例所属类的原型(prototype)。原型对象中有一个属性constructor,它指向函数对象。

1
2
3
4
5
6
7
function Person() {
    var person = new Person();
    console.log(person.__proto__ === Person.prototype); //true
    console.log(Person.prototype.constructor === Person); //true
    //顺便学习一个ES5的方法,可以获得对象的原型
    console.log(Object.getPrototypeOf(person) === Person.prototype); //true
}

(2)什么是原型链?

当我们在访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。如果没有则取原型的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined

原型链总结

(1)原型链的终点?

原型链的终点是null

1
Object.prototype.__proto__ === null;

(2)什么是原型链?prototype

原型链是实例对象原型对象之间的链接

(3)为什么要使用原型链?

  • 为了实现继承,简化代码,实现代码重用!只要是这个链条上的内容,都可以被访问和使用到!
  • 避免了代码冗余,公用的属性和方法,可以放到原型对象中,这样,通过该构造函数实例化的所有对象都可以使用该对象的构造函数中的属性和方法!
  • 减少了内存占用

(4)原型链的特点

每个继承父函数的实例对象都包含一个内部属性proto。该属性包含一个指针,指向父函数的prototype。若父函数的原型对象的proto属性为再上一层函数。在此过程中就形成了原型链。

(5)总结

  • 每个函数(class)都有prototype属性
  • 每个对象(实例)都有proto属性,指向了创建该对象的构造函数的原型
  • 实例的proto指向对应class的prototype
  • 对象可以通过proto来寻找属于该对象的属性,proto将对象连接起来组成了原型链
Built with Hugo
主题 StackJimmy 设计