一、概念
1、所有的引用类型(数组、函数、对象)可以自由扩展属性(除null以外)。也就是说,可以使用Obj.prototype={}来添加新的属性。
2、所有的引用类型都有一个’_ _ proto_ _'属性(也叫隐式原型,它是一个普通的对象)。
3、所有的函数都有一个’prototype’属性(这也叫显式原型,它也是一个普通的对象)。
4、所有引用类型,它的’_ _ proto_ _'属性指向它的构造函数的’prototype’属性。
5、当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,
那么就会去它的’_ _ proto_ _'属性(也就是它的构造函数的’prototype’属性)中去寻找。
二、原型
原型的英文:prototype 。
function Person(name) {
this.name = name;
}
Person.prototype = {
sayHi: function () {
console.log('Hi , my name is ' + this.name + '!');
}
}
var yancy = new Person('yancy');
console.log('yancy.__proto__: ',yancy.__proto__);
console.log('Person.prototype: ',Person.prototype);
yancy.sayHi();
其实[[prototype]]和__proto__意义相同,均表示对象的内部属性,其值指向对象原型。前者在一些书籍、规范中表示一个对象的原型属性,后者则是在浏览器实现中指向对象原型。
如图,yancy 对象并没有syaHi方法属性,但是我们给它的构造函数Person添加了sayHi属性,所以它可以直接调用sayHi()。这个sayHi属性是在它的__proto__ 属性里找到的,更准确的说,是__proto__ 所指向的Person构造函数的prototype 对象属性中定义的sayHi属性,也就是原型中的属性。
为什么要使用原型呢?
不使用原型,只需要在构造函数Person中,直接定义sayHi属性。yancy一样可以直接调用。但是,这样是存在缺陷的,如果我利用Person构造了许多实例对象,那么每个实例对象中都包含了sayHi属性,看似并没有什么不妥。然而,既然这些实例对象中的sayHi属性都是一模一样的,为什么不提取出来呢? 于是js引入了原型的概念。
三、原型链
当前对象调用属性,发现自己没有,便去__proto__也就是构造函数的prototype属性中去找,如果构造函数的prototype属性中没有找到,那么就会去构造函数的prorotype属性(也是对象)的__proto__中(也就是其构造函数的protype属性中找),依次类推,指导找到了Object的__proto__(为null),如果依旧没找到,那么就没有该属性。
如图: (1)、如果yancy.sayHi(),则会在Person.prototype中找到sayHi属性并调用。 (2)、如果yancy.toString(),则会在Object.prototype中找到toString属性并调用。
四、typeof和instanceof
(1)、typeof
typeof运算符用于判断对象的类型。
基本用法为 typeof obj
var number = 1;
var str = 'Hello World!';
var array = [];
var yancy = {
name : 'yancy',
age: 20
}
console.log(typeof number);
console.log(typeof str);
console.log('typeof array: ',typeof array);
console.log('typeof yancy: ',typeof yancy);
可以看到,对于数组和对象,typeof的判定结果都为object。
所以不能使用typeof来判断对象是不是数组,那么就需要用到下面的instanceof了。
(2)、instanceof
instanceof相比与typeof来说,instanceof方法要求开发者明确的确认对象为某特定类型。
即instanceof用于判断引用类型属于哪个构造函数的方法。
更重要的一点是 instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型。
var array = [];
console.log('array instanceof Array: ',array instanceof Array);
console.log('array instanceof Object: ',array instanceof Object);
判断实例对象是否在函数的原型链上:
function Person(name) {
this.name = name;
}
Person.prototype = {
sayHi: function () {
console.log('Hi , my name is ' + this.name + '!');
}
}
var yancy = new Person('yancy');
可以看到yancy对象是在构造函数Person原型链上的。
|