记录JS原型心得体会

263 阅读3分钟

原型是什么东西?

只要是对象就有原型, 并且原型也是对象, 因此只要定义了一个对象, 那么就可以找到他的原型, 如此反复, 就可以构成一个对象的序列, 这个结构就被成为原型链。 原型链继承就是利用就是修改原型链结构( 增加、删除、修改节点中的成员 ), 从而让实例对象可以使用整个原型链中的所有成员( 属性和方法 )。

普通对象与函数对象

var o1 = {}; 
var o2 = new Object();
var o3 = new f1();

function f1(){}; 
var f2 = function(){};
var f3 = new Function('str','console.log(str)');

console.log(typeof Object); //function 
console.log(typeof Function); //function  

console.log(typeof o1); //object 
console.log(typeof o2); //object 
console.log(typeof o3); //object

console.log(typeof f1); //function 
console.log(typeof f2); //function 
console.log(typeof f3); //function

在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function() 的方式进行创建的。Function Object 也都是通过 New Function() 创建的。

原型对象

原型对象,顾名思义,它就是一个普通对象。原型对象就是 Person.prototype ; 每个函数对象都有一个 prototype 属性,这个属性指向函数的原型对象。 每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性。 在默认情况下,所有的原型对象都会自动获得一个 constructor (构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Person)。 原型对象(Person.prototype)是 构造函数(Person)的一个实例。

Person.prototype.constructor == Person
var abc = function(){
  this.name="小明";
}
// 函数对象
abc.prototype.say=function(){
    alert(this.name);
}
var a = new abc();
a.say();  
//小明

// 这么做的好处是不会额外产生内存,
// 所有实例化后的对象都会从原型上继承这个方法

构造函数(constructor)

JS 在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做 __proto__ 的内置属性,用于指向创建它的构造函数的原型对象。 对象 person1 有一个 __proto__ 属性,创建它的构造函数是 Person ,构造函数的原型对象是 Person.prototype ,所以:person1.__proto__ == Person.prototype

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() { alert(this.name) } 
}
var person1 = new Person('Zaxlct', 28, 'Software Engineer');
var person2 = new Person('Mick', 23, 'Doctor');

// person1 和 person2 都是 Person 的实例。
// 实例的构造函数属性(constructor)指向构造函数。
//构造函数
function Foo(name,age){
    this.name = name
    this.age = age
    this.class = 'class-1'
}
//实例化
var f1 = new Foo('Jon',20);
var f2 = new Foo('daming',22);

f1.constructor == Foo; //true

f1.__proto__ == Foo.prototype //true
//__proto__用于指向创建它的构造函数的原型对象。

Foo.prototype.constructor == Foo; //true
//实例的构造函数属性(constructor)指向构造函数。`
function Person(){}
var person1 = new Person();
console.log(person1.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype) //true
console.log(Object.prototype.__proto__) //null

Person.__proto__ == Function.prototype; //true
console.log(Function.prototype)// function(){} (空函数)

var num = new Array()
console.log(num.__proto__ == Array.prototype) // true
console.log( Array.prototype.__proto__ == Object.prototype) // true
console.log(Array.prototype) // [] (空数组)
console.log(Object.prototype.__proto__) //null

console.log(Array.__proto__ == Function.prototype)// true

如上图所展示的,原型对象指向构造函数的指针是 constructor ,构造函数的 prototype 指向原型对象,构造函数通过 new 操作符来创建一个实例 , 实例又可以通过内部指针 __proto__ 指向原型对象。 __proto__ 连接的这一条原型对象就构成了原型链。

Person.prototype.constructor == Person;
person1.__proto__ == Person.prototype;
person1.constructor == Person;
var animal = function(){};
var dog = function(){};

animal.price = 2000;
dog.prototype = animal;
var tidy = new dog();
console.log(dog.price) //undefined
console.log(tidy.price) // 2000

实例(tidy)和 原型对象(dog.prototype)存在一个连接。不过,要明确的真正重要的一点就是,这个连接存在于实例(tidy)与构造函数的原型对象(dog.prototype)之间,而不是存在于实例(tidy)与构造函数(dog)之间。