目录
# 1.原型
(1)所有的引用类型(对象、数组、函数),除了
null
,都具有对象特性,可自由扩展属性;(2)所有的引用类型(对象、数组、函数)都有一个
__proto__
属性,属性值是一个普通的对象;(3)所有的引用类型(对象、数组、函数)的
__proto__
属性值,指向它的构造函数的prototype
属性值;(4)所有的函数,都有一个
prototype
属性,属性值也是一个普通的对象
示例:
//1,所有的引用类型可自由扩展属性
var obj = {};
var arr = [];
function fn() {}
obj.a = 1;
arr.a = 1;
fn.a = 1;
console.log('obj', obj);
console.log('arr', arr);
console.log('fn.a', fn.a);
//2,所有的引用类型都有一个_proto_属性
console.log('obj.__proto__', obj.__proto__);
console.log('arr._proto_', arr.__proto__);
console.log('fn._proto_', fn.__proto__);
//4,所有的函数,都有一个prototype熟悉,属性值是一个对象
console.log('fn.prototype', fn.prototype);
//3,所有的引用类型的_proto属性值,指向它的构造函数的prototype属性值
console.log(obj.__proto__ === Object.prototype); //true
对于示例中的 obj,在控制台打印出来可以发现,它除了具有属性 a 外,还有一个__proto__
属性,属性值是一个普通对象:
当试图得到一个对象的某个属性时,如果该对象没有这个属性,就会去该属性的_proto_
(即该对象的构造函数的prototype
)中找。
# 2.原型链
示例:
//构造函数
function Person(name) {
this.name = name;
}
Person.prototype.showName = function() {
alert(this.name);
};
//创建实例
var person1 = new Person('peter');
person1.printName = function() {
console.log('name is:', this.name);
};
person1.printName();
person1.showName();
person1.toString();
console.log('Person.prototype', Person.prototype);
console.log('Person.prototype.__proto__', Person.prototype.__proto__);
person1 本身有 printName,但当试图执行 person1.showName 时,由于对象本身没有这个属性时,那么会去它的proto,即它的构造函数的 prototype 中去寻找。在上述示例中,person1.showName 就会去它的构造函数 Person 的 prototype 中去寻找,就会找到 Person.prototype.showName。
当试图执行 person1.toString 时,由于 person1 本身没有 toString,因此去 person1.proto(即 Person.prototype)中去找,发现没有找到,继续往上找。person1.proto.proto(即 Person.prototype.proto)中去找,Person.prototype 就是一个普通对象,因此,Person.prototype.proto就是 Object.prototype,在这里可以找到 toString()。即 person1.toString 最终向上找到了 Object.prototype.toString。
整个过程:
person1 没有找到 toString,往上找;
person1.proto即 Person.prototype,没有找到 toString,继续往上找;
person1.proto.proto即 Person.prototype.proto,即Object.prototype
,可以找到 toString:
这样通过__.proto__
一直往上找,就是一个链式结构,即“原型链
”。如果找到原型链的最上册都没有找到,就会返回undefined
,宣布失败。
上述 2 原型链的示例中,在执行 person1.printName()、person1.showName()时,this 是什么呢?
所有从原型或更高级原型中得到的方法,this
指向当前触发事件执行的对象,因此这里 printName()、showName 中的 this,都是 person1
下面祭出这张图,参考:
所有的对象都可以通过proto找到 Object,Object 是所有对象的基类(父类)
所有的函数都可以通过proto找到 Function,Function 是所有函数的基类(父类)
所有的引用类型默认都继承了 Object,这个继承是通过原型链实现的;
所有的函数的默认原型也是 Object 的实例,因此默认原型都会包含一个内部的指针,指向 Object.prototype。这也是自定义类型都会继承 toString()、valueOf()等默认方法的根本原因。
那么如何判断这个属性是对象本身的属性呢?可以使用hasOwnProperty()
:
还是继续使用上述 1 中的示例:
console.log('person1.hasOwnProperty(printName)', person1.hasOwnProperty('printName')); //true
console.log('person1.hasOwnProperty(showName)', person1.hasOwnProperty('showName')); //false
# 3.小结
本篇 JS 基础知识总结,主要是分别结合一些示例,介绍了原型、原型链的基本知识。如有问题,欢迎指正。