一.原型
1.1对象的原型
-
定义
js当中每个对象都有一个特殊的内置属性[[ prototype ]] (隐式原型),这特殊的对象可以指向另一个对象
-
作用
- 当我们通过引用对象的属性key来获取一个value时,它就会触发[[Get]]的操作
- 这个操作首先会检查该对象是否有对应的属性,若有就返回该属性
- 如果对象中没有该属性,那么就会访问对象[[prototype]]内置属性指向的对象上的属性
-
获取方法
方式一: 通过对象的__proto__属性可以获取到(浏览器提供,纯在一定的兼容性问题) 方式二:通过Object.getPrototypeOf()方法获取
1.2函数对象的原型(重点显示原型)
- 定义
(函数是特殊的对象)将函数看成一个普通对象是,它具备_ proto_(隐式原型)
作用:查找key对应的value时,会找到原型身上
将函数看作是一个函数时(非箭头函数),它是具备prototype(显式原型)
作用:用来构建对象时,给对象设置隐式原型的
-
作用
当一个函数被new操作符操作了会经历如下的过程。
- 在内存中创建一个新的对象(空对象)
- 这个对象内部的[[prototype]] (隐式原型)属性会被赋值为该构造函数的prototype属性
- 构造函数内部的this,会指向创建出来的新对象
- 执行函数的内部代码(函数体代码)
- 如果构造函数没有返回非空对象,则返回创建出来的新对象
-
用处
当多个对象拥有共同的值时,可以将该值放到构造函数对象的显式原型,由构造函数创建出来的所有对象,都会共享这些属性
function Foo(name,age,height){ this.name = name this.age = age this.height = height // 方法一:直接定义。(创建多个实例时,会创建多个函数对象) // this.put = function(){ // console.log(this.name,this.age,this.height); // } } // 方法二:将函数挂载到Foo的原型上 Foo.prototype.put = function(){ console.log(this.name,this.age,this.height); } var foo1 = new Foo('lsp',18,178) foo1.put()
1.2.1 constructor属性
原型对象上有一个属性叫做constructor
在显示原型上constructor指向当前的函数对象
function Foo(){}
var foo1 = new Foo()
console.log(Foo.prototype.constructor);//function Foo
console.log(foo1.__proto__.constructor);//function Foo
console.log(foo1.__proto__.constructor.name);//Foo
二. 继承(ES5)
2.1前言
面向对象的三大特性:封装,继承,多态
- 封装:将属性和方法封装到一个类中
- 继承:减少重复代码的数量,也是多态的前提(纯面向对象中)
- 多态:执行时表现出不同的形态
原型链:从一个对象上获取属性,如果当前对象中没有获取到就会去它的原型上获取
2.2利用原型链实现继承
2.2.1方法继承
// 父
function Person(name,age,height){
this.name = name
this.age = age
this.height = height
}
Person.prototype.eating=function(){
console.log("eating");
}
// 子
function Student(){}
// 方式一:父类原型直接赋值给子类原型
// 缺点:父子类共享一个原型对象,修改其中一个,另一个也会跟着变化
// Student.prototype=Person.prototype
// var stu=new Student()
// stu.eating()
// 方法二:创建一个父类的实例对象,用这个实例对象作为子类的原型对象
//缺点:只能继承方法,属性时无法继承的
var p = new Person('lsp','18','188')
Student.prototype = p
var stu = new Student()
stu.eating()
2.2.2属性继承
// 父
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.eating=function(){
console.log("eating");
}
// 子
function Student(name,age,height,hobby){
// this.name = name
// this.age = age
// 重点:借用构造函数
Person.call(this,name,age)
this.height = height
this.hobby = hobby
}
2.2.3组合借用继承
将方法继承第二种与属性继承结合起来被称作组合借用继承,有缺陷
2.2.4寄生组合式(最终)
//寄生组合式函数
//将该函数封装起来,方便使用
function createObject(o){
function F(){}
F.prototype = o
return new F()
}
function inherit(Subtype,SuperType){
Subtype.prototype = createObject(SuperType.prototype)
Object.defineProperty(Subtype.prototype,"constructor",{
enumerable: false,
configurable: true,
writable: true,
value: Subtype
})
}
// -----------------
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.eating=function(){
console.log("eating");
}
function Student(name,age,height,hobby){
Person.call(this,name,age)
this.height = height
this.hobby = hobby
}
inherit(Student,Person)
Student.prototype.stydying = function(){
console.log("studying");
}
//创建实例对象
var stu = new Student('lsp','18','188',"肉蛋冲击")
2.2Object类是所有类的父类
所有对象的原型链终点是object(object的原型是null)