原型
prototype 原型 函数一声明天生就有
原型的概念:原型是一个可以被复制(或者叫克隆)的一个类,通过复制原型可以创建一个一模一样的新对象。通俗的说,原型就是一个模板,在设计语言中更准确的说是一个对象模板。
原型模式: 是用于创建重复的对象,同时又能保证性能,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
(1): 原型是定义了一些公用的属性和方法,利用原型创建出来的新对象实例会共享原型的所有属性和方法
//实例
//创建原型
function Person(name){
this.name = name
}
// 原型的方法
Person.prototype.sayYhl = function(){
console.log(this.name + ", hello");
};
//实例化对象
var per = new Person("Jack");
var per2 = new Person("Tom");
per.sayYhl(); //Jack, hello
per2.sayYhl(); //Tom, hello
(2): 严格模式下,原型的属性和方法还是会被原型实例所共享的
// 开启严格模式,原型的属性和方法还是会被原型实例所共享的
"use strict";
// 创建原型
var Person = function(name){
this.name = name;
};
// 原型的方法
Person.prototype.sayHello = function(){
console.log(this.name+",hello");
};
// 实例化创建新的原型对象,新的原型对象会共享原型的属性和方法
var per = new Person("Jack");
var per2 = new Person("Tom");
// Jack,hello
per.sayHello();
// Tom,hello
per2.sayHello();
(3):通过原型创建的新对象实例是相互独立的,为新对象实例添加的方法只有该实例拥有这个方法,其它实例是没有这个方法的
// 创建原型
var Person = function(name){
this.name = name;
};
// 原型的方法
Person.prototype.sayYhl = function(){
console.log(this.name+",hello");
};
// 实例化创建新的原型对象,新的原型对象会共享原型的属性和方法
var per = new Person("Tom");
var per2 = new Person("Jack");
// Tom,hello
per.sayYhl();
// Jack,hello
per2.sayYhl();
// 为新对象实例添加方法
// 通过原型创建的新对象实例是相互独立的
per.getName = function(){
console.log(this.name);
}
// Tom
per.getName();
// Uncaught TypeError: per2.getName is not a function
per2.getName();
从属关系
prototype -> 函数的一个属性 : 对象 {}
proto -> 对象Object的一个属性 :对象{}
对象的__proto__保存着该对象的构造函数prototype
function Yhl(){}
console.log(Yhl.prototype);
const yhl = new Yhl();
console.log(yhl.__proto__);
console.log(yhl.__proto__ === Yhl.prototype); //true
console.log(Yhl.prototype.__proto__ === Object.prototype); //true
console.log(Object.prototype.__proto__); // null
如图所示:
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
原型的总结:
- 所有引用类型都有一个
__proto__
(隐式原型)属性,属性值是一个普通的对象 - 所有函数都有一个prototype(原型)属性,属性值是一个普通的对象
- 所有引用类型的
__proto__
属性指向它构造函数的prototype
原型的分类
隐式原型(_proto_)
:上面说的这个原型是JavaScript中的内置属性[[prototype]],此属性继承自object对象,在脚本中没有标准的方式访问[[prototype]],但Firefox、Safari和Chrome在每个对象上都支持一个属性
_proto_
,隐式原型的作用是用来构成原型链,实现基于原型的继承
显示原型(prototype):每一个函数在创建之后,便会拥有一个prototype属性,这个属性指向函数的原型对象,显示原型的作用是用来实现基于原型的继承与属性的共享
原型链
1)原型链:原型链是原型对象创建过程的历史记录,当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构
2)原型设计的问题:当查找一个对象的属性时,JavaScript 会根据原型链向上遍历对象的原型,直到找到给定名称的属性为止,直到到达原型链的顶部仍然没有找到指定的属性,就会返回 undefined 也可以理解为原型链继承时查找属性的过程是先查找自身属性,当自身属性不存在时,会在原型链中逐级查找
3)hasOwnProperty 函数:可以用来检查对象自身是否含有某个属性,返回值是布尔值,当属性不存在时不会向上查找对象原型链,hasOwnProperty
是 JavaScript 中唯一一个处理属性但是不查找原型链的函数
//console.log(mc.hasOwnProperty("age"));
4)getOwnPropertyNames 函数:可以获取对象所有的自身属性,返回值是由对象自身属性名称组成的数组,同样不会向上查找对象原型链
5)原型链总结
- 一直往上层查找,直到到null还没有找到,则返回undefined
Object.prototype.__proto__ === null
- 所有从原型或更高级原型中的得到、执行的方法,其中的this在执行时,指向当前这个触发事件执行的对象