对象编程语言基础

对象操作-v1.0.0

2019-07-28  本文已影响0人  一点金光
---
title: 对象操作
date: 2018-06-09 16:29:00
updated: 2018-06-10 12:00:00
categories:
- 语法基础
- 对象编程
tags:
- nodejs
---

目录

有何特点
如何创建
如何继承
何时多态

正文

有何特点
抽象、封装、继承、多态

如何创建
工厂、构造、原型、构造+原型、动态原型、Object.creat(es5)、class(es6)

//对象化-对象创建的几种方式


// 方案-es6
// constructor方法与构造函数模式相似
// class上的方法都是定义在prototype上的,这又跟原型模式有一些相似之处
// 缺点1:必须使用new进行调用
// 注:class不存在变量提升,es5中的function存在变量提升。
// class内部定义的方法不可枚举,es5在prototype上定义的方法可以枚举
class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    toString() {
        return '(' + this.x + ', ' + this.y + ')';
    }
}

// 方案-es5
// https://segmentfault.com/a/1190000002979437
var Point = Object.create(Object.prototype, {
    x: {
        value: 0;
        // 可遍历否
        //enumerable: false,
        // 是否可删
        //configurable: false,
        // 是否可写
        //writable: false
    },
    y: {
        value: 0;
        // 可遍历否
        //enumerable: false,
        // 可删除否
        //configurable: false,
        // 可写入否
        //writable: false
    }
});

// 方案-构造模式+动态原型模式
// 构造函数用于定义实例属性和方法(各个实例私有)
// 原型属性用于定义共享属性和方法(各个实例共享)
// 动态理解:在这里对原型所做的修改,能够立刻在所有实例中得到反映。
// 注:这段代码只会在初次调用构造函数时才执行。
function Point(x, y) {
    this.x = x;
    this.y = y;
    if(typeof this.toString != "function") {
        Point.prototype.toString = function() {
            return '(' + this.x + ',' + this.y + ')';
        };
    }
}

// 方案-构造模式+原型模式
// 构造函数用于定义实例属性和方法(各个实例私有)
// 原型属性用于定义共享属性和方法(各个实例共享)
// 优点1:把共享和私有的分开。
// 注:在es6出现之前使用最普遍的一种创建对象模式
function Point(x, y) {
    this.x = x;
    this.y = y;
}
Point.prototype.toString = function() {
    return '(' + this.x + ',' + this.y + ')';
}

// 方案-原型模式 -写法1
// 有一个prototype属性,指向一个对象;
// 这个对象的用途是包含一些共享属性和方法;
// 函数的构造函数默认是它本身
// 优点1:将所有的属性和方法都定义在其prototype属性上,达到这些属性和方法能被所有的实例所共享的目的。
// 缺点1:当一个对象上的属性改变时,所有对象上的属性也会随之改变。
function Point() {}
Point.prototype.toString = function() {
    return '(' + this.x + ',' + this.y + ')';
}
// 方案-原型模式 -写法2
// 这种写法改写了constructor构造指向为Object,需要重新设置constructor属性
function Point() {}
Point.prototype = {
    // 重新设置构造指向
    constructor: Point,
    toString: function() {
        return '(' + this.x + ',' + this.y + ')';
    }
};
// 方案-原型模式 -写法3
// 这种写法改写了constructor构造指向为Object,需要重新设置constructor属性
function Point() {}
Point.prototype = {
    toString: function() {
        return '(' + this.x + ',' + this.y + ')';
    }
};
Object.defineProperty(Point.prototype, "constructor", {
    enumerable: false,
    value: Point,
});

// 方案-构造模式
// 优点1:与工厂模式相比,能够辨别一个对象到底是Person还是Dog,亦或是Cat。
// 缺点1:实例化对象时,需在该函数前面加一个new关键字。
// 缺点2:构造函数里的属性和方法在每个对象上都要实例化一遍,包括对象共用的属性和方法。造成了代码复用性差的问题。
function Point(x, y) {
    // 使用this
    this.x = x;
    this.y = y;
    this.toString = function() {
        return '(' + this.x + ',' + this.y + ')';
    };
}

// 方案-工厂模式
// 优点1:代码复用
// 缺点1:创建的对象的构造函数全都是Object,没有辨识度。
function Point(x, y) {
    // 在一个函数内创建好对象,然后把对象返回
    var o = new Object();
    o.x = x;
    o.y = y;
    o.toString = function() {
        return '(' + this.x + ',' + this.y + ')';
    };
    return o;
}
// 方案-对象字面量
// 缺点1:只能一个一个去创建,每一个对象的方法和属性都需要单独写
// 优点1:与Object构造函数相比,简单直观
var Point = {
    x: 0,
    y: 0,
    toString: function() {
        return '(' + this.x + ',' + this.y + ')';
    }
}

// 方案-Object构造函数
// 缺点1:只能一个一个去创建,每一个对象的方法和属性都需要单独写
var Point = new Object();
Point.x = x;
Point.y = y;
Point.toString = function() {
    return '(' + this.x + ',' + this.y + ')';
};

// es6-class 转es5-class
// https://fed.renren.com/2017/08/07/js-oop-es52es6/
// es6代码:
class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    toString() {
        return '(' + this.x + ', ' + this.y + ')';
    }
}
// es5代码:
'use strict'; // es6中class使用的是严格模式

// 处理class中的方法
var _createClass = function () { 
    // 定义属性函数
   function defineProperties(target, props) { 
      for (var i = 0; i < props.length; i++) { 
         var descriptor = props[i]; 
         // 可遍历否
         descriptor.enumerable = descriptor.enumerable || false; 
         // 可删除否
         descriptor.configurable = true; 
         // 可写入否
         if ("value" in descriptor) descriptor.writable = true; 
         // 对象定义属性(对象,键名,描述)
         Object.defineProperty(target, descriptor.key, descriptor);
      } 
   } 
   // 返回构造渲染函数
   return function (Constructor, protoProps, staticProps) { 
      // 共用的=>写在原型属性上
      if (protoProps) defineProperties(Constructor.prototype, protoProps); 
      // 私有的=>写在构造函数上
      if (staticProps) defineProperties(Constructor, staticProps); 
      return Constructor; 
   }; 
}();

// 对构造函数进行判定
function _classCallCheck(instance, Constructor) { 
   if (!(instance instanceof Constructor)) { 
      throw new TypeError("Cannot call a class as a function"); 
   }
}

// class Point转换为 es5的function
var Point = function () {
    function Point(x, y) {
        // 调用了_classCallCheck检查Person是否为构造函数
        _classCallCheck(this, Point); 
        this.x = x;
        this.y = y;
    }

    // 调用_createClass处理定义在class中的方法。
    _createClass(Point, [{
        key: 'toString',
        value: function toString() {
           return '(' + this.x + ', ' + this.y + ')';
        }
    }]);

    return Point;
}();

如何继承
拷贝继承、原型继承、类似继承、extends(es6)

/对象化-对象继承的几种方式

//方案--拷贝继承
function extendObj1(obj1, obj2) {
    for(var attr in obj2) {
        obj1[attr] = obj2[attr];
    }
}

//方案--拷贝继承--改进版
function extendObj2() {
    // 存储参数
    var args = arguments;
    if(args.length < 2) return;

    // 复制对象
    var temp = cloneObj(args[0]);
    // 合并对象
    for(var n = 1; n < args.length; n++) {
        for(var i in args[n]) {
            // 普通模式
            //if(args[n].hasOwnProperty(i) && (!temp.hasOwnProperty(i))) temp[i] = args[n][i];
            // 覆盖模式
            temp[i] = args[n][i];
        }
    }
    return temp;
}

//复制对象-深复制
function cloneObj(oldObj) {
    if(typeof(oldObj) != 'object') return oldObj;
    if(oldObj == null) return oldObj;

    var newObj = {};
    for(var i in oldObj) {
        newObj[i] = cloneObj(oldObj[i]);
    }
    return newObj;
}


//方案--原型继承
function cloneProto(obj) {
    var F = function() {};
    F.prototype = obj;
    return new F();
}
var b = cloneProto(a);
b.name = '小乔';
alert(a.name);
alert(b.name);

//方案--类式继承
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();
//https://www.cnblogs.com/simonryan/p/4828791.html

function clone(value, isDeep) {
    if(value === null) return null;
    if(typeof value !== 'object') return value;
    // 数组
    if(Array.isArray(value)) {
        // 深复制
        if(isDeep) {
            return value.map(item => clone(item, true))
        }
        // 浅复制
        return [].concat(value)
    }
    // 对象
    else {
        // 深复制
        if(isDeep) {
            var obj = {}
            Object.keys(value).forEach(item => {
                obj[item] = clone(value[item], true)
            })
            return obj
        }
        // 浅复制
        return { ...value
        }
    }
}

// 对象复制-浅复制
// 方案1
let obj2 = Object.assign({}, {
    name: 'zhang',
    age: 10,
    friends: ['1', 2, 23]
})

// 方案2:Object.getOwnPropertyDescriptors方法的另一个用处,是配合Object.create方法

// 方案3
function extendCopy(p) {    
    var c = {};    
    for(var i in p) {      
        c[i] = p[i];    
    }       
    return c; 
}

/*
var Chinese = {  
    nation: '中国'
}
var Doctor = {  
    career: '医生'
} 
var Doctor = extendCopy(Chinese);  
Doctor.career = '医生';  
alert(Doctor.nation); // 中国
*/

// 对象复制-深复制
// 方案1
// 缺点:只针对数组或者对象,函数不行
let obj2 = JSON.parse(JSON.stringify({
    name: 'zhangsan',
    friends: ['lisi', 'baoqiang', 'dada']
}))

// 方案2
function deepCopy(p, c) {    
    var c = c || {};    
    for(var i in p) {      
        if(typeof p[i] === 'object') {        
            c[i] = (p[i].constructor === Array) ? [] : {};        
            deepCopy(p[i], c[i]);      
        } else {         
            c[i] = p[i];      
        }    
    }    
    return c;  
}

var Chinese = {
    nation: '中国'
}
var Doctor = {
    career: '医生'
}
var Doctor = deepCopy(Chinese);
Chinese.birthPlaces = ['北京', '上海', '香港'];
Doctor.birthPlaces.push('厦门');

console.log(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
console.log(Chinese.birthPlaces); //北京, 上海, 香港

何时多态

上一篇 下一篇

猜你喜欢

热点阅读