对象操作-v1.0.0

作者: 一点金光 | 来源:发表于2019-07-28 00:09 被阅读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); //北京, 上海, 香港

何时多态

相关文章

  • 对象操作-v1.0.0

    目录 有何特点如何创建如何继承何时多态 正文 有何特点抽象、封装、继承、多态 如何创建工厂、构造、原型、构造+原型...

  • 数组操作-v1.0.0

    目录 克隆扁平连接拼接截取排序添加删除遍历映射过滤某一符合所有符合包含生产转化复杂查找填充包含 正文 #克隆 #扁...

  • 函数操作v1.0.0

    目录 函柯里化函数节流函数防抖 正文 函柯里化 函数节流 函数防抖

  • 字符操作-v1.0.0

    目录 es5es6 正文 es5 es6

  • 原型操作v1.0.0

    针对浏览器端的Object的原型进行操作现在已经不提倡做直接操作dom

  • 浏端操作-v1.0.0

    title: 浏端操作date: 2018-06-09 16:29:00updated: 2018-06-10 1...

  • Git 删除github上某个tag/release

    github中删除release/tag只能在命令执行,不能界面点击操作 例子: 删除一个 v1.0.0 的rel...

  • 舟山医后付SDK集成文档v1.0.0

    舟山医后付SDK集成文档v1.0.0 名称: 舟山医后付SDK集成文档V1.0.0版本: V1.0.0作者: 宋珍...

  • VBS 文件操作

    '操作文本文件,操作fso对象(文件对象操作) ---------------------------------...

  • VBS文件操作

    VBS文件操作'操作文本文件,操作fso对象(文件对象操作) --------------------------...

网友评论

    本文标题:对象操作-v1.0.0

    本文链接:https://www.haomeiwen.com/subject/evgyrctx.html