理解对象
内部属性特征:数据属性特征和访问器属性特征 数据属性特征
[[Configurable]]:能否通过delete删除属性;能够修改属性的特征;能够把数据属性特征修改为访问器属性特征。默认为true [[Enumerable]]:能否通过for-in循环返回属性。默认为true [[Writable]]:能否修改属性的值。默认为true [[Value]]:这个属性的数据值。默认为undefined 访问器属性特征
[[Configurable]]:能否通过delete删除属性;能够修改属性的特征;能够把访问器属性特征修改为数据属性特征。默认为true [[Get]]:读取属性时的行为。默认为undefined
-[[Set]]:写入属性时的行为。默认为undefined 修改或定义属性的特征:Object.defineProperty() var person={};
Object.defineProperty(person,"name" ,{
writable:false ,
value:"Chris"
});
复制代码
var book={
_year:2014,
edition:1
};
Object.defineProperty(book,"year" ,{
get:function (){
return this._year;
},
set :function (newValue){
if (newValue>2014){
this._year=newValue;
this.edition+=newValue-2014;
}
}
})
复制代码
只能通过对象方法访问的属性:前置下划线记号。 定义多个属性:Object.defineProperties() Object.getOwnPropertyDescriptor() 创建对象
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.sayName=function (){
alert(this.name);
}
}
var o = new Object();
Person.call(o,"Kris',25," Doctor");
Person.sayName();//" Kris"
复制代码
原型模式
通过调用构造函数创建实例对象的原型对象 所有实例对象共享原型对象的属性和方法 任何函数都有prototype属性,这个属性指向函数的原型对象 原型对象会有一个constructor属性,这个属性指向拥有该prototype属性的函数 对象的实例拥有属性[[Prototype]],指向原型对象 所有实现都无法访问[[Prototype]],但是可以通过isPrototypeOf()方法来确定对象之间的关系。如果实例内部存在指向prototype的指针,那么isPrototypeOf()返回true。Person.prototype.isPrototypeOf(person1)
(确定实例与原型之间的关系) 通过Object.getPrototypeOf()
可以方便地取得一个对象的原型 不能通过实例对象重写原型中的值,实例对象与原型对象重名的属性会屏蔽掉原型对象中的属性 hasOwnProperty()判断属性是否是实例中的,当给定属性存在于对象实例中时才返回true in操作符,单独使用时,无论属性存在于实例还是原型中时都返回true。只有当属性在实例和原型中都搜索不到时才会返回false。 for-in循环会返回的是能通过对象访问的,可枚举的属性。屏蔽了原型中不可枚举的实例属性也会在for-in循环中返回。 Object.keys()返回所有可枚举属性的字符串 Object.getOwnPropertyNames()返回所有属性 function Person (){
Person.prototype.name="Kris" ;
Person.prototype.age=25;
Person.prototype.job="Doctor" ;
Person.prototype.sayName=function (){
alert(this.name);
}
}
复制代码
function Person (){
}
Person.prototype={
name:"Kris" ,
age:29,
job:"Doctor" ,
sayName:function (){
alert(this.name);
}
}
//上面的操作改变了Person Prototype中constructor的指向(指向Object)。
Object.defineProperty(Person.prototype,"constructor" ,{
enumerable:false ,//默认情况下,constructor是不可枚举的
value:Person//简化语法会导致constructor指向Object
})
复制代码
原型模式的问题,省略了通过构造函数传递初始化参数这一环节。并且对于引用类型的属性,共享成为了问题。 组合使用构造函数模式和原型模式
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.friend=["Bob" ,"Kevin" ]//使用构造函数定义实例属性
}
Person.prototype={
constructor:Person,
sayName:function (){
alert(this.name);
}//使用原型模式定义方法以及需要共享的属性
}
复制代码
动态原型模式
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
//初始化原型方法
if (typeof this.sayName!="function" ){
Person.prototype.sayName=function (){
alert(this.name);
};
}
}
复制代码
寄生构造函数模式 稳妥构造函数模式 继承
js只支持实现继承,即extends。依靠原型链实现。 让原型对象等于另一个类型的实例。关键代码SubType.prototype=new SuperType()
SubType的原型指向SuperType的原型,SuperType原型的constructor指向SuperType。所以所有SubType实例的constructor都指向SuperType 确定原型与实例的关系
instanceof instance instanceof Object
isPrototypeOf Object.prototype.isPrototypeOf(instance)
子类重写父类的方法或者子类添加父类中不存在的方法,这些语句需要放在继承语句(即替换原型的语句之后)。并且不能使用对象字面量创建原型方法 原型链继承的问题
借用构造函数 function SubType (){
//支持传递参数
SuperType.call(this,"Kris" );
//添加子类属性
this.age=29;
}
复制代码
组合继承
使用原型链完成方法继承 使用借用构造函数完成属性和引用类型的继承 function SubType(name,age){
//继承属性
SuperType.call(this,name);
this.age=29;
}
SubType.prototype=new SuperType();
SubType.prototype.constructor=SubType;
SubType.prototype.sayName()=function (){
alert(this.name);
}
复制代码
原型式继承:Object.create()
本质上是对传入参数对象进行一次浅复制,因此引用类型属性全实例共享 接受参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性 返回值:一个新对象,带着指定的原型对象和属性。 o = Object.create(Object.prototype, {
// foo会成为所创建对象的数据属性
foo: {
writable:true ,
configurable:true ,
value: "hello"
},
// bar会成为所创建对象的访问器属性
bar: {
configurable: false ,
get: function () { return 10 },
set : function (value) {
console.log("Setting `o.bar` to" , value);
}
}
});
复制代码
寄生式继承
对父对象进行一次浅复制 在封装函数中对复制后的对象进行方法增强 无法做到函数复用 function createAnother(original){
var clone =Object.create(original);
clone.sayHi=function (){
alert("hi" );
};
return clone ;
}
复制代码
寄生组合式继承
原有组合继承,无论什么情况下都会调用两次超类的构造函数 使用构造函数来继承属性,使用原型链的混成形式来继承方法 function inheritPrototype(subType,superType){
//获取父类的原型副本
var prototype=Object.create(superType.prototype);
//为创建的副本添加constructor
prototype.constructor=subType;
//将新创建的原型副本指定为子类的原型
subType.prototype=prototype;
}
function SubType(name,age){
SuperType.call(this,name);
this.age=age;
}
inheritPrototype(SubType,SuperType);
复制代码
只调用一次父类的构造函数,避免在子类的原型上创建多余的属性。是引用类型最理想的继承范式
转载于:https://juejin.im/post/5d08db3be51d45109725fe89