原型及相关概述
prototype
(函数的属性:对象{})
原型是JavaScript独有的行为继承机制。主要内容是每个JavaScript函数在创建的时候默认会向该函数添加一个属性(
prototype
),这个属性对应一个Object对象,称为原型对象(原型在程序里面默认就是一个Object对象)
- 函数作为普通函数调用prototype没有任何作用
- 通过函数创建的对象可以直接使用原型对象上的行为。
- 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中,继承的基础
- Object类是JavaScript自带的一个类,默认该类的对象会作为所有函数的原型对象。
- 我们给原型上添加行为,通过函数生成的对象也可以使用新增的行为
- 各自函数的原型不是同一个对象
__proto__
(对象Object的一个属性:对象{})
原型的链接点
其实不属于构造函数的原型,而是来自于Object.prototype
当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过
__proto__
来访问该属性function Person() {} var person = new Person(); console.log(person.__proto__ === Person.prototype); // true
当读取实例属性时候,如果找不到,就去继承原型中的属性,如果还查不到?那咋整?当然是再去找原型的原型喽,知道找到最顶层为止
function Person() {} Person.prototype.name = 'Kevin'; var person = new Person(); person.name = 'Daisy'; console.log(person.name) // Daisy //删除person自身属性name delete person.name; //输出的为原型对象的属性 console.log(person.name) // Kevin
这里面的首先给实例原型赋属性值name为“Kevin”,下面给实例化对象也赋值属性name为“Daisy”,第一遍访问person的name属性时,值为“Daisy”,delete之后,实例化本身的name已经为空,所以再次访问的时候,就会往上一层寻找name属性,即通过prototype赋的name值,所以这时的值是“Kevin“。
对象的__proto__
保存着该对象构造函数的prototype
constructor
构造函数的
prototype
指向原型,原型对象的constructor
指向构造函数function Person() {} var person=new Person(); console.log(Person === Person.prototype.constructor); // true console.log(person.constructor === Person.prototype.constructor)//true
可以被更改
原型的原型
原型对象也是对象,所以它也有原型,
当我们使用一个对象的属性或方法时,会现在自身中寻找,
自身中如果有,则直接使用
如果没有则去原型对象中寻找,如果原型对象中有,则使用,
如果没有则去原型的原型中寻找,直到找到Object对象的原型,
Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined
console.log(Person.prototype.__proto__===Object.prototype) //true console.log(Object.prototype.__proto__)//null
原型链
概念
以一个对象为基准,
__proto__
为连接的链条,一直到Object.prototype.__proto__
为止
- JavaScript 每个对象都有一个私有属性
__proto__
指向它的构造函数的原型对象prototype
。该原型对象也有一个__proto__
,层层向上直到一个对象的原型对象__proto__
为null
,作为这个原型链中的最后一个环节 - 当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,会在该对象的原型链上依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾
- 意义:在ES5中实现继承
Function和Object的特殊性
Function
和Object
既是函数又是对象
function Text(){}
console.log(Text.__proto__===Function.Prototype);//true
//Text构造底层原理
const Text=new Function()
//底层规范 Function 构造了本身
console.log(Function.__proto__===Function.prototype)//true
console.log(typeof Object)//function
console.log(Object.__proto__===Function.prototype)//true
console.log(Function.__proto__===Object.__proto__)//true
判断对象中是否包含某属性
hasOwnProperty
判断某个属性是否是自身的属性,不考虑继承过来的属性。console.log(text.hasOwnProperty('name'));
in
判断某个属性是否是自身的属性,考虑继承过来的属性console.log('name' in text);
继承(ES5)
语法
function Son(name){ this.name = name; } function Father(phone){ this.phone =phone; } function GrandPa(money){ this.money = money; } //用原型链实现继承 //老爸继承爷爷 Father.prototype = new GrandPa(100000000); //儿子继承老爸 Son.prototype = new Father('10086'); let s = new Sun('张三'); console.log(s.money);
存在的问题
- 继承的属性值是默认的,固定的,不符合继承的实现
解决方案
子构造函数的原型设置为父构造函数的实例对象
子函数名.prototype = new 父函数名();
子函数第一行利用
Call
让子函数创建出来的对象拥有父构造函数中定义的属性和行为function 子函数(参数1,参数2,参数n){ 父函数名.call(this,参数1,参数2,参数n); }
注:call 本身是JavaScript的一个内置函数(之后会再进行补充)
作用:能够改变一个函数的执行环境,实现’借用’
语法
函数名.call(新的执行环境,函数调用需要的参数);
以新的执行环境调用一次函数,函数所需的参数,是从call的第二个实际参数开始。
在ES5中的作用’
- 把子类作为父类构造函数的执行环境并执行一次父类的构造。目的是为了子类对象拥有父类构造函数里定义的属性和行为