一、对象创建
1.对象属性:
Object对象类型是原型链的最外层
实例对象->先查找自己本身下面的属性和方法->自身没找到会沿着原型链找到该对象的原型,再查看原型上是否有要查找的属性或方法->依次继续查找如果找到的话则返回,否则找到最顶层Object上还没有就真没有了
2.对象创建方式
2.0 对象创建过程
实例化obj对象有三步:
1. 创建obj空对象:obj=new Object();
2. 将obj的内部__proto__指向构造他的函数A的prototype,同时,obj.constructor===A.prototype.constructor(这个是永远成立的,即使A.prototype不再指向原来的A原型,也就是说:类的实例对象的constructor属性永远指向"构造函数"的prototype.constructor);
3. 将obj作为this去调用构造函数A,从而设置成员(即对象属性和对象方法)并初始化。
2.1、工厂方式创建对象:面向对象中的封装函数(内置对象)
function createPerson(name){ //1、原料 var obj=new Object(); //2、加工 obj.name=name; obj.showName=function(){ alert(this.name); } //3、出场 return obj; } var p1=createPerson('小米'); p1.showName();
与系统对象的区别:
var arr=new Array();//生成一个系统数组对象
1、系统对象是直接用 new 在外面生成,而工厂定义的是在函数内部生成
2、工厂定义的函数名称第一个是小写开头,而系统定义的是大写开头
工厂模式的优缺点:虽然解决了创建相似对象的问题,但是却没有解决对象识别问题(即怎样知道一个对象的类型)。
2.2、构造函数创建对象
当new去调用一个函数,这个时候函数中的this就是创建出来的对象,而且函数的返回值就是this(隐式返回)
new后面的函数叫做构造函数
<1>有参数的构造函数
function CreatePerson(name){ this.name=name; this.showName=function(){ alert(this.name); } } var p1=new CreatePerson('小米');
<2>无参数的构造函数
function CreatePerson(){} var p1=new CreatePerson(); p1.name="小米"; p1.showName=function(){ alert(p1.name); } p1.showName();
构造函数模式的优缺点:
1、优点:创建自定义函数意味着将来可以将它的实例标识为一种特定的类型,这是构造函数胜过工厂模式的地方
2、缺点:每个方法都要在每个实例上重新创建一遍
2.3、对象字面量方式创建对象
person={
name:"小米",
age:23
};
2.4、用原型方式
1、原型对象:只要创建了一个新函数,就会为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性是一个指向prototype属性所在函数的指针
2、可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系
function Person(){} Person.prototype.name="小米"; Person.prototype.showName=function(){ alert(this.name); } var p1=new Person(); p1.showName();
原型模式的优缺点:
1、优点:可以让所有的对象实例共享它所包含的属性和方法
2、缺点:原型中是所有属性都是共享的,但是实例一般都是要有自己的单独属性的。所以一般很少单独使用原型模式。
2.5.混合模型
构造函数模式定义实例属性,而原型模式用于定义方法和共享的属性
function CreatePerson(name){ this.name=name; } Create.prototype.showName=function(){ alert(this.name); } var p1=new CreatePerson('小米'); p1.showName();
var p2=new CreatePerson('小米'); p2.showName();
alert(p1.showName==p2.showName);//true;原因:都是在原型下面,在内存中只存在一份,地址相同
2.6 Object.create()
var obj = Object.create({x:1,y:2});//obj继承了属性x和y
3. 属性特性
属性的特性其实就是值当前的属性是否可以写可以读等等。即外部对象对于属性操作的权限。
当前的js一般的属性都是有4中特性。分别是:数值性value,可写性writable,可枚举性enumerable,和可配置性configurable。但是由于对象中存在一类特别的属性存取器属性,所以对于存取器属性的值实际上是有点不同的,他有自己的特别的属性特性包括,读取(get),写入(set),可枚举和可配置。为了实现这一对象属性的描述,js中定义了一个属性描述符对象。并且可以通过Object.getOwnPropertyDescriptor()方法来获取某个对象中的特定属性的描述符。当然当前函数只能获取对象自有属性的描述,如果要获取继承属性的描述符的话,需要使用Object.getPrototypeOf();
当然我们可以使用Object.defineProperty方法进行对象内容的进行相关的编辑,如下
1 Object.defineProperty({},"x", {value:1, writable:true, enumerable:true, configurable:true}); 2 //这是将返回一个对象,并且其中设定了一个可读写,枚举和配置的属性x 3 4 //当然如果要修改的对象本身其中就有一个这一属性,然后想通过这一方法配置的话。也是可以的。 5 6 //特性对象中的内容可以不用写全,当添加属性的时候未写明的内容将会直接设置成为false或是undefined。而在修改属性的时候未写明的内容将不会有任何改变。
4.属性枚举
- for/in循环遍历当前的对象的内容是一种很常见的手段。其可以遍历对象中的所有的可枚举属性,包括当前对象的自有属性和继承属性。
- Object.key()方法,枚举属性名称的函数,他返回的是一个数组,其中存在的是对象中的可枚举属性名称组成。
- Object.getOwnPropertyNames()方法,其返回的额也是数组,但是是所有的自有属性名称的数组。
二、继承方式:
1、拷贝继承:通用型 有new无new都可以用
2、类式继承:new构造函数---利用构造函数(类)继承的方式
3、原型继承:无new的对象---借助原型来实现对象继承对象
属性继承:调用父类的构造函数call
方法继承:用for in的形式 拷贝继承(jq也用拷贝继承)
var a = { name: '小米' }; //拷贝继承 function extend(obj1, obj2) { for (var attr in obj2) { obj1[attr] = obj2[attr]; } } //原型继承 var b=cloneObj(a); b.name='小乔'; alert(a.name); alert(b.name); function cloneObj(obj) { var F=function () {}; F.prototype=obj; return new F(); } //类式继承 function A() {//父类 this.name='小米'; } A.prototype.showName=function () { alert(this.name); } function B() {//子类 A.call(this);//属性和方法分开继承 }
//B.prototype=new A();//一句话实现继承,但会有很多问题,比如指向问题,属性会互相影响
//类式继承改进:至少由以下四句实现方法的继承,属性需要分开继承
var F=function () {}; F.prototype=A.prototype; B.prototype=new F(); B.prototype.constructor=A;//修正指向问题 var b1=new B(); b1.name='笑笑'; b1.showName();