资讯专栏INFORMATION COLUMN

JavaScript_面向对象程序设计

lingdududu / 1488人阅读

摘要:构造函数用于检测给定的属性在当前对象实例中而不是原型中是否存在。返回对象的字符串表示。实现空函数的原型对象和超类的原型对象转换原型继承做善后处理。判断父类的原型对象的构造器,防止简单原型中给更改为还原父类原型对象的构造器

类的创建于实例对象 工厂模型创建对象
function CreatePerson ( name,sex,age ) {
    
    var obj = new Object();
    
    obj.name = name;
    obj.sex = sex;
    obj.age = age;
    
    obj.sayName = function () {
        
        console.log( this.name );
        
    }
    
    return obj;
    
}

var p1 = CreatePerson("zf","女",22);

p1.sayName(); //zf

console.log( p1.name );  //zf
构造函数式
//函数的第一个字母大写(类的模板)
function Person ( name,age,sex ) {
    
    this.name = name;
    this.age = age;
    this.sex =sex;
    
    this.sayName = function () {
        
        alert(this.name);
        
    }
    
}

//构造一个对象,  使用new关键字, 传递参数,   执行模板代码, 返回对象。

var p1 = new Person("zf",20,"女");  //类的概念:根据模板创建出不同的实例对象
 
console.log( p1.name );

p1.sayName();

创建类的实例:

当作构造函数去使用

var p1 = new Person("a1",20);

作为普通函数去调用

Person("a2",20); //在全局环境中定义属性并赋值, 直接定义在window上。

在另个一对象的作用域中调用

var o = new Object();
Person.call(o,"a3",23);

Object每个实例都会具有的属性和方法:

Constructor: 保存着用于创建当前对象的函数。(构造函数)
hasOwnProperty(propertyName):用于检测给定的属性在当前对象实例中(而不是原型中)是否存在。
isPrototypeOf(Object): 用于检查传入的对象是否是另外一个对象的原型。
propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for-in语句来枚举。
toLocaleString():返回对象的字符串表示。该字符串与执行环境的地区对应.
toString():返回对象的字符串表示。
valueOf():返回对象的字符串、数值或布尔表示。

判断一个对象是不是另一个对象的实例,通常使用的是 instanceof. 比较少使用constructor。

原型

创建每一个函数的时候,都有一个prototype属性. 这个是属性,是一个指针。而这个对象总是指向一个对象。
这个对象 的用途就是将特定的属性和方法包含在内,是一个实例对象, 起到了一个所有实例所共享的作用。
屏蔽了,构造函数的缺点,new 一个对象,就把构造函数内的方法实例化一次。

function Person () {
                
}

var obj = Person.prototype;

console.log( obj );  //Person.prototype 就是一个对象
//Person.prototype 内部存在指针,指针指向一个对象。 这个对象称之为:原型对象。原型对象,被所有的实例对象所共享。

console.log( obj.constructor ); //function Person(){}  //obj这个对象的构造器就是 Person

原型图例:

console.log(Person.prototype) 的结果:

常用方法 Object.getPrototypeOf()

根据实例对象获得原型对象

每次代码读取一个对象的属性的时候:首先会进行一次搜索,搜索实例对象里,看看是否存在,如果没有,再去实例所对的原型中寻找属性.如果有则返回,如果两次都没有则返回undefined

function Person () {
}

Person.prototype.name = "z1";
Person.prototype.age = 20;

Person.prototype.sayName = function () {
    
    console.log( "我是原型对象方法" );
    
}

var p1 = new Person();

console.log( p1.name ); //z1

console.log( Object.getPrototypeOf(p1) );  
console.log( Object.getPrototypeOf(p1) == Person.prototype ); //true
hasOwnProperty()

判断是否是 实例对象自己的属性

function Person () {
}

Person.prototype.name = "z1";
Person.prototype.age = 20;

Person.prototype.sayName = function () {
    
    console.log( "我是原型对象方法" );
    
}


// 判断一个对象属性 是属于 原型属性 还是属性 实例属性

var p3 = new Person();    
console.log( p3.name ); //zf 是原型上的

//hasOwnProperty() 是否是 实例对象自己的属性 
console.log( p3.hasOwnProperty("name") ); //false 
in 操作符

无论是 原型的属性, 还是实例对象的属性, 都区分不开。 如果存在,返回true

function Person () {
}

Person.prototype.name = "z1";
Person.prototype.age = 20;

Person.prototype.sayName = function () {
    
    console.log( "我是原型对象方法" );
    
}


//判断属性是否存在 实例对象 和 原型对象中. 

var p1 = new Person();
console.log("name" in p1); //true  //表示,name的属性到底在不在p1的属性中  true
var p2 = new Person();

p1.name = "zzz";

console.log("name" in p1); //true

判断一个属性是否在原型中

function Person () {
}

Person.prototype.name = "z1";
Person.prototype.age = 20;

Person.prototype.sayName = function () {
    
    console.log( "我是原型对象方法" );
    
}


//判断属性是否存在 实例对象 和 原型对象中. 

var p1 = new Person();
p1.name = "123";

//在原型对象中,是否存在这个值
//@obj 当前对象
//@判断的属性
function hasPrototypeProtoperty ( obj,attrName ) {
    
    return !obj.hasOwnProperty(attrName) && (attrName in obj);
    
}

console.log( hasPrototypeProtoperty(p1,"name") );  //false
Object.keys()
function Person () {
}

Person.prototype.name = "z1";
Person.prototype.age = 20;

Person.prototype.sayName = function () {
    
    console.log( "我是原型对象方法" );
    
}

//ECMA5新特性  Object.keys(); 
//拿到当前对象中的所有keys, 返回一个数组

var p1 = new Person();
p1.name = "zz";
p1.age = 20;

var attr = Object.keys(p1);
console.log( attr );  //["name", "age"]

var attr2 = Object.keys(p1.__proto__);  

console.log( attr2 );  //["name", "age", "sayName"]

var attr3 = Object.keys(Person.prototype);  

console.log( attr3 );  //["name", "age", "sayName"]
Object.getOwnPropertyNames()
function Person () {
}

Person.prototype.name = "z1";
Person.prototype.age = 20;

Person.prototype.sayName = function () {
    
    console.log( "我是原型对象方法" );
    
}

var p1 = new Person();
p1.name = "zz";
p1.age = 20;

//ECMA5 
//constructor属性,是无法被枚举的. 正常的for-in循环是无法枚举. [eable = false];

//Object.getOwnPropertyNames(); //枚举对象所有的属性:不管该内部属性能够被枚举.

var attr4 = Object.getOwnPropertyNames(Person.prototype); //["constructor", "name", "age", "sayName"]

console.log( attr3 );
isPrototypeOf()

判断原型的方法

原型对象.isPrototypeOf(new instance);

实现each方法

原型的另外一个作用就是扩展对象中的属性和方法

//遍历多维数组
var arr = [1,2,4,5,[455,[456,[345345]]]];


Array.prototype.each = function ( cb ) {

    try {

        //计数器
        this.i || (this.i = 0);

        //核心代码
        if ( this.length > 0 && cb.constructor === Function ) {

            while ( this.i < this.length ) {  //计数器 大于 数组长度跳出

                //获得每一项值    
                var e = this[this.i];

                //判断是否是 数组
                if ( e && e.constructor === Array ) {

                    //递归
                    e.each(cb);

                } else {

                    cb.call(null,e);

                }

                this.i++;    

            }

            //使用完之后,释放变量
            this.i = null;

        }


    } catch (e) {
        //do someting
        
    }

    return this;

};


arr.each(function( val ){

    console.log(val);

});
简单原型

直接通过对象字面量来重写整个原型对象(这种方法会改变原型对象的构造器[改变为Object])

//简单原型
            
function Person () {
    
}

Person.prototype = {
    
    constructor: Person,  //原型的构造器改变
    
    name: "zz",
    age: 20,
    
    say: function () {
        console.log( this.age );
    }
    
}

var p1 = new Person();

console.log( p1.name );
p1.say();

存在的问题,constructor属性是无法被枚举的。加在原型对象上,可以被枚举,被枚举。不符合要求。

ECMA5中的Object.defineProperty()方法可以为原型对象重新加入构造器。constructor问题可以被避免。

//3个参数,  参数1:重新设置构造的对象 (给什么对象设置)     参数2:设置什么属性        参数3:options配置项 (要怎么去设置)
Object.defineProperty(Person.prototype,"constructor",{
    enumerable: false,  //是否是 能够 被枚举
    value: Person  //值   构造器的 引用
});

原型的动态特性

注意原型和创建实例的前后顺序

function Person () {
                        
}

var p1 = new Person();  // {}
 
Person.prototype = {
    constructor: Person,
    name: "zf",
    age: 20,
    say: function () {
        console.log("原型");
    }
}

//先把原型对象写好,然后再实例化。

//p1.say();    //error 因为      原型对象里面没有任何属性和方法

var p2 = new Person();

p2.say();

//注意  简单原型使用的顺序(实例对象必须在原型对象之后创建)

原型对象的常用开发模式 组合构造函数式和原型模式
function Person( name,age,firends ) {
    
    this.name = name;
    this.age = age;
    this.firends = firends;
    
}

Person.prototype = {
    constructor: Person,
    sayName: function () {
        console.log( this.name );
    }
}

var p1 = new Person("zz",20,["zf"]);
var p2 = new Person("zx",22,["z1"]);

console.log( p1.firends ); //["zf"]                
console.log( p2.firends );  //["z1"]
动态原型模式

就是把信息都封装到函数中,这样体现了封装的概念。

//动态原型模式:(让你的代码  都封装到一起)
function Person( name,age,firends ) {
    
    this.name = name;
    this.age = age;
    this.firends = firends;
    
    //动态原型方法
    if ( typeof this.sayName !== "function"  ) {
        
        Person.prototype.sayName = function () {
            console.log(this.name);
        }
        
    }
    
}
稳妥构造函数式

稳妥模式就是没有公共属性,而且其他方法也不引用this对象,稳妥模式最适合在安全的环境中使用。如果程序对于安全性要求很高,那么非常适合这种模式。
也不能使用new关键字。

//稳妥构造函数式  durable object (稳妥对象)
//1,没有公共的属性
//2,不能使用this对象

function Person ( name,age ) {
    
    //创建一个要返回的对象。  利用工厂模式思维。
    var obj = new Object();
    
    //可以定义一下是有的变量和函数 private
    
    var name = name || "zf";
    
//                        var sex = "女";
//                        var sayName = function () {
//                        }

        
    //添加一个对外的方法
    obj.sayName = function () {
        console.log(name);
    }
    
    return obj;
    
}

var p1 = Person("xixi",20);

p1.sayName();    

深入原型继承的概念

如果让原型对象等于另一个类型的实例,结果会怎么样呢?显然此时的原型对象将包含一个指向另一个原型的指针,相应的另一个原型中也包含着一个指向另一个构造函数的指针。

原型链: 利用原型让一个引用类型继承另外一个引用类型的属性和方法。

构造函数 原型对象 实例对象

构造函数.prototype = 原型对象

原型对象.constructor = 构造函数

实例对象.__proto__ = 原型对象

原型对象.isPrototypeOf(实例对象)

构造函数 实例对象 (类和实例)

isPrototypeOf(); //判断是否 一个对象的 原型

//父类的构造函数  Sup
function Sup ( name ) {
    
    this.name = name;
    
}

//父类的原型对象
Sup.prototype = {
    constructor: Sup,
    sayName: function () {
        console.log(this.name);
    }
}

//子类的构造函数 Sub
function Sub ( age ) {
    
    this.age = age;
    
}

//如果子类的原型对象  等于 父类的 实例

//1, 显然此时的原型对象将包含一个指向另一个原型的指针
//2, 相应的另一个原型中也包含着一个指向另一个构造函数的指针。

//            实例对象.__proto__ = 原型对象
//                Sup的实例对象  和 Sup的原型对象 有一个关系

Sub.prototype = new Sup("zf");

//            console.log( Sub.prototype.constructor );  //function Sup () {}
//            
//            console.log( Sub.prototype.__proto__ );    //Sup 的 原型对象


var sub1 = new Sub(20);

console.log( sub1.name );  //zf
sub1.sayName();  //zf

原型链继承映射图

继承的三种方式 原型继承
//原型继承的特点:
//即继承了父类的模板,又继承了父类的原型对象。  (全方位的继承)
//父类
function Person ( name,age ) {
    
    this.name = name;
    this.age = age;
    
}

Person.prototype.id = 10;

//子类
function Boy ( sex ) {
    
    this.sex = sex;     
    
}

//原型继承
Boy.prototype = new Person("zz");

var b = new Boy();

console.log( b.name ); //zz
console.log( b.id ); //10
类继承

类继承 (只继承模板) 不继承原型对象 (借用构造函数的方式继承)

//父类
function Person ( name,age ) {
    
    this.name = name;
    this.age = age;
    
}

Person.prototype.id = 10;

//子类
function Boy ( name,age,sex ) {
    
    //类继承
    Person.call(this,name,age);
    
    this.sex = sex;     
    
}

var b = new Boy("zf",20,"女");

console.log( b.name ); //zf
console.log( b.age ); //20
console.log( b.sex );  //女
console.log( b.id );  //父类的原型对象并没有继承过来.

    
混合继承

原型继承+类继承

    
    //父类     (关联父类和子类的关系)
function Person ( name,age ) {
    
    this.name = name;
    this.age = age;
    
}

Person.prototype.id = 10;
Person.prototype.sayName = function () {
    console.log( this.name );
}

//子类
function Boy ( name,age,sex ) {
    
    //1 类继承
    Person.call(this,name,age);   //继承父类的模板
    
    this.sex = sex;     
    
}                

//2 原型继承
//父类的实例  和 父类的 原型对象的关系.
Boy.prototype = new Person();   //继承父类的原型对象

var b = new Boy("z1",20,"女");

console.log( b.name );//z1
console.log( b.sex ); //女
console.log( b.id ); //10

b.sayName(); //z1    
ExtJs底层继承方式

模拟ExtJs底层继承一部分代码

//ExtJs  继承
//2件事: 继承了1次父类的模板,继承了一次父类的原型对象


function Person ( name,age ) {
    
    this.name = name;
    this.age = age;
    
}

Person.prototype = {
    
    constructor: Person,
    
    sayHello: function () {

        console.log("hello world!");

    }
    
}

function Boy ( name,age,sex ) {
    
    //call 绑定父类的模板函数  实现  借用构造函数继承  只复制了父类的模板
    
//                Person.call(this,name,age);

        Boy.superClass.constructor.call(this,name,age);
    
    this.sex = sex;        
    
}

//原型继承的方式: 即继承了父类的模板,又继承了父类的原型对象。
//            Boy.prototype = new Person();
//只继承 父类的原型对象
    extend(Boy,Person);  // 目的 只继承 父类的原型对象  , 需要那两个类产生关联关系.

//给子类加了一个原型对象的方法。
Boy.prototype.sayHello = function () {
    
    console.log("hi,js");
    
}

var b = new Boy("zf",20,"男");

console.log( b.name );
console.log( b.sex );
b.sayHello(); 

Boy.superClass.sayHello.call(b);

//extend方法

//sub子类, sup 父类
function extend ( sub,sup ) {
    
    //目的, 实现只继承 父类的原型对象。   从原型对象入手
    
    //1,创建一个空函数, 目的:空函数进行中转
    var F = new Function();  // 用一个空函数进行中转。
    
//                把父类的模板屏蔽掉, 父类的原型取到。
    
    F.prototype = sup.prototype;  //2实现空函数的原型对象 和 超类的原型对象转换
    
    sub.prototype = new F();  //3原型继承
    
    //做善后处理。 还原构造器 ,
    sub.prototype.constructor = sub;  //4 ,还原子类的构造器
    
//                保存一下父类的原型对象  // 因为 ①方便解耦, 减低耦合性      ② 可以方便获得父类的原型对象
    sub.superClass = sup.prototype;   //5 ,保存父类的原型对象。   //自定义一个子类的静态属性   , 接受父类的原型对象。
    
    //判断父类的原型对象的构造器, (防止简单原型中给更改为  Object)
    if ( sup.prototype.constructor == Object.prototype.constructor ) {
        
        sup.prototype.constructor = sup;  //还原父类原型对象的构造器
        
    }
    
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79713.html

相关文章

  • 面向对象JavaScript

    摘要:是完全的面向对象语言,它们通过类的形式组织函数和变量,使之不能脱离对象存在。而在基于原型的面向对象方式中,对象则是依靠构造器利用原型构造出来的。 JavaScript 函数式脚本语言特性以及其看似随意的编写风格,导致长期以来人们对这一门语言的误解,即认为 JavaScript 不是一门面向对象的语言,或者只是部分具备一些面向对象的特征。本文将回归面向对象本意,从对语言感悟的角度阐述为什...

    novo 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    李昌杰 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    Lyux 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    AaronYuan 评论0 收藏0
  • JavaScript设计模式与开发实践 | 01 - 面向对象JavaScript

    摘要:在中,并没有对抽象类和接口的支持。例如,当对象需要对象的能力时,可以有选择地把对象的构造器的原型指向对象,从而达到继承的效果。本节内容为设计模式与开发实践第一章笔记。 动态类型语言 编程语言按数据类型大体可以分为两类:静态类型语言与动态类型语言。 静态类型语言在编译时已确定变量类型,动态类型语言的变量类型要到程序运行时,待变量被赋值后,才具有某种类型。 而JavaScript是一门典型...

    suxier 评论0 收藏0
  • JS对象(1)重新认识面向对象

    摘要:对象重新认识面向对象面向对象从设计模式上看,对象是计算机抽象现实世界的一种方式。除了字面式声明方式之外,允许通过构造器创建对象。每个构造器实际上是一个函数对象该函数对象含有一个属性用于实现基于原型的继承和共享属性。 title: JS对象(1)重新认识面向对象 date: 2016-10-05 tags: JavaScript 0x00 面向对象 从设计模式上看,对象是...

    superw 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<