对象操作-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); //北京, 上海, 香港
何时多态