美文网首页
面向对象-包装对象,继承,深度克隆

面向对象-包装对象,继承,深度克隆

作者: 一刀一个小黄鱼 | 来源:发表于2017-07-20 23:26 被阅读20次

包装对象

为什么字符串,数字等基础类型是没有属性和方法的。那么我们平时创建了一个字符串(非字符串对象)的时候,为什么可以调用他length,indexOf等属性或方法?

内置对象:js提供已经定义好的对象,如Array,Date,RegExp,String,Number,Boolean等,同时js定义好了一些对应的一些构造函数

为什么字符串,数字等基础类型是没有属性和方法的。那么我们平时创建了一个字符串(非字符串对象)的时候,为什么可以调用他length,indexOf等属性或方法?

这就是包装对象:

当我们去调用字符串,数字,布尔值这三种基础数据类型的属性和方法的时候,他们本身是不具备属性和方法的,但是js内部,会自动的去调用他们对象的构造函数,然后把他们的值作为参数进行传入,然后执行对应属性或方法,并把结果进行返回。

包装对象一共有三个: String,Number,Boolean

var a = String('123')
console.log(typeof a,a) //String 123

var b = new String('123')
console.log(typeof b,b) //Object {0:'1',1:'2',2:'3'}
/*可以看到是一个对象,在它的__proto__里的有各种方法*/
//创建一个基本字符串类型的数据
var str = "abcdefg";
//调用方法 indexOf ,str本身是没有indexOf方法的
var s = str.indexOf("b");

//那么js会自动在内部调用str的对应构造函数方法,同时,把str的值作为该次的调用的参数
new String(str).indexOf("b")
var s2 = new String(str).indexOf("b");

String就是一个字符串数据的包装对象


如果我们尝试给字符串,数字,布尔值增加自定义的属性和方法的时候,是无效的

 var str2 = "abcdef";
str2.a = 100;
str2.length = 1000;
console.log(str2.a); // undefined 相当于new String(str2).a
console.log(str2.length); // 6 相当于new String(str2).length

所以当一个字符串被申明以后,其值就不会发生改变,除非重新覆盖,所以我们把字符串值又成为字符串常量 - 字面量

修改toString()

Object对象prototype下的一个方法,所有对象都继承该方法

既然是在Object的prototype里面,那就可以自己修改toString方法

function Creat(){}
var c1 = new Creat;
Object.prototype.x = 100;
console.log(c1.x) //因为之前说过,自身找不该属性方法,就会一直往上找,最后找到Object

Creat.prototype.toString = function(){
  console.log("我是构造函数toString")
}
c1.toString();  //"我是构造函数toString";
Array.prototype.toString = function(){
  var result = 0;
  for (var i = 0;i < this.length;i++){
    result += this[i]
  }
  return result;
}

alert([1,2,3]);//6
hasOwnProperty()

判断某个属性(方法)是否是某个对象自有的,就是非原型链上的

function Person(){
  this.name = "小明"
}
Person.prototype.x = 100;
var p1 = new Person();

console.log( p1.hasOwnProperty('name') ); //true
console.log( p1.hasOwnProperty('x') ); //false
constructor

属性:返回某个对象的构造函数(可写)

var a = [1,2,3];
console.log(a.constructor == Array); //true;

a.constructor = 1;
console.log(a.constructor); //1
console.log(a.constructor == Array); //false;
instanceof

属性:判断一个对象是否是某个构造函数的实例化对象

var a = [1,2,3];
console.log(arr instanceof Array); //true

function Creat(){}
var b = new Creat;
cosole.log(b instanceof Creat); //true

当我们使用面向对象的方法,去构建不同的函数时,可能有些元素对象功能是一样的,但有些地方不一样,就需要有不同的方法

继承

拷贝继承

<style type="text/css">
    .show {
      width: 200px;
      height: 200px;
      background: red;
    }
</style>
<div id="box1"></div>
<div id="box1"></div>
function Creat(elment){
  var _this = this;
  this.el = elment;
  this.el.className = "show";
  this.el.onclick = function(){
    _this.active();
  }
  this.el.onmouseover = function(){
    _this.hover();
  }
  this.el.onmouseout = function(){
    _this.end();
  }
}
Creat.prototype.active = function(){
  this.el.style.backgroundColor = "blue"
}
Creat.prototype.hover = function(){
  this.el.style.backgroundColor = "green"
}
Creat.prototype.end = function(){
  this.el.style.backgroundColor = "red"
}
var box1 = document.querySelector("#box1");
var box2 = document.querySelector("#box2");
new Creat(box1);
//new creat(box2);

如果我们用同一个方法这时就2个元素的属性方法都是一样,点击都会变成蓝色,可我们想每个元素点击使用不同的背景色,这时可以用call改变this指向来完成

function CreatLimit(elment){
  Creat.call(this,elment) //Creat,并把Creat中this指向CreatLimit的this
}
//这时还需要把Creat.prototype里面的active给传过来
CreatLimit.prototype = Creat.prototype
//new CreatLimit(box2) 这时还是不行我们点击还是蓝色
CreatLimit.prototype.active = function(){
  this.el.style.backgroundColor = "yellow"
}

当我们有多个函数方法相同,但只有一个不一样时需要修改的情况,这时会发现box2点击是黄色的了,但是再点击box1会发现box1也变成黄色了,这就涉及到一个赋值和赋址的情况

赋值和赋址

var a = 1;
var b = a;
b = 2;
console.log(a) //a还是1

var arr1 = [1,2,3];
var arr2 = arr1;
arr2.push(4)
console.log(arr1) //[1,2,3,4]

当我们把arr2和arr1建立关系时,这时他们在内存里(数据都是存储在内存里运行)的地址是同一个,这个时候修改arr2就是修改这个地址的数据,arr1使用这个地址数据就是修改后的,如果是

arr2 = [1,2,3,4] 这个是单独是给arr2赋值,并没有修改地址里的那个数据,所以arr1还是[1,2,3]

如果我们是通过赋址的形式,那么会有问题,因为现在是对象赋址,那么CreatLimit.prototype的修改会影响Creat.prototype

那么我们可以把Creat.prototype中的属性和方法一个个的赋值给CreatLimit.prototype

CreatLimit.prototype.active =Creat.prototype.active
CreatLimit.prototype.hover =Creat.prototype.hover
CreatLimit.prototype.end =Creat.prototype.end
CreatLimit.prototype.active = function(){
  this.el.style.backgroundColor = "yellow"
}
//这时因为是单独把值赋给CreatLimit.prototype.active下,在修改覆盖之前的active后,并不会对box1产生影响。
//为了方便。我们可以使用forin在批量动态的处理这些属性和方法,forin不只是会把Drag.prototype自身的属性循环出来,还会把一些原型链上的属性和方法也循环出来

for(var property in Creat.prototype){
  CreatLimit.prototype[property] =Creat.prototype[property]
}
CreatLimit.prototype.active = function(){
  this.el.style.backgroundColor = "yellow"
}

类式继承

//在上面方法forin更改为
CreatLimit.prototype = new Creat(box1)
CreatLimit.prototype.active = funciton(){
  console.log(2)
}
//测试用
var c2 = new CreatLimit(box2) 
c2.active();

让CreatLimit的prototype指向Creat的一个实例对象,这样的话CreatLimit的prototype和Creat.prototype就没有直接引用关系,但是因为CreatLimit的prototype是Creat的一个实例,那么CreatLimit的prototype自动会查找Creat的prototype

通过CreatLimit的prototype可以找到Creat的prototype下,但是CreatLimit的prototype和Creat的prototype又没有直接的关系

基于原型链查找过程:

c2.active => c2.proto.active => CreatLimit.prototype.active =>new Creat(box1).proto.active =>

Creat.prototype.active

这只是继承的2种方法,还有其他很多方法,网上都有分享

深度克隆

var obj1 = {
  x: 10,
  y: 20
}
var obj2 = obj1;
obj2.x = 20;
console.log(obj1.x) //20
console.log(obj2.x) //20

由于:obj2和obj1是引用关系,obj2的修改会影响到obj1,就需要把obj1中的值单独赋值给obj2

var obj2 = {};
for (var propety in obj1){
  obj2[propety] = obj1[propety]
}
obj2.x = 100;
console.log(obj1.x) //10
console.log(obj2.x) //100

但是可能obj1里存在对象,或者数组,就还需要在forin到obj1下面的数组里面,可是又是不知道 数组或者对象下面还存不存在数组或者对象,这时就需要递归来寻找

var obj1 = {
  x: 10,
  y:20,
  attr: {a: 1},
  arr: [1,2,3],
  z: null
};

function extend(originObject) {
  var newObject = Array.isArray(originObject)?[]:{};//判断原始数据是数组还是对象
  for (var propety in originObject) {
    if(typeof originObject[propety] == 'object'&& originObject[propety] != null)//判断是否是个对象
      newObject[property] = extend(originObject[property]);
    //递归克隆
  } else {
     newObject[property] = originObject[property];
  }
}
    return newObject;
}

var obj2 = extend(obj1);
obj2.attr.b = 2;
console.log(obj2.attr);
console.log(obj1.attr);

根据originObject的原始类型来对新对象进行对应的初始化,保证进来什么格式出去就是什么格式,如果出去也是对象,但是传进来是个数组就不行
如果当前数据是对象的话,那么就需要进行深度克隆,注意:typeof来判断数据类型是有一个小的问题的,null的typeof结果也是object,所以需要排除null值的深度克隆

以上!

相关文章

  • 面向对象-包装对象,继承,深度克隆

    包装对象 为什么字符串,数字等基础类型是没有属性和方法的。那么我们平时创建了一个字符串(非字符串对象)的时候,为什...

  • JavaScript之面向对象编程

    五、面向对象编程 目录:面向对象原型继承、面向对象class继承(ES6引入的) 1.面向对象原型继承 类:模板 ...

  • 王艳华Pythonday03

    Python的面向对象 Java 面向对象 继承

  • Python面向对象继承

    面向对象继承 面向对象编程 (OOP),英语全称:Object Oriented Programming,面向对象...

  • js公共函数总结

    字节大小转换 Object 对象的深度克隆(深拷贝) 时间格式化 js利用空对象作为中介实现继承 需求:get请求...

  • 面向对象:创建对象&继承

    博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...

  • java基础-day10-面向对象4.0

    面向对象4.0 1. 面向对象之继承 1.1 生活中的继承 1.2 Java中的继承 1.3 子类对象创建,会调...

  • 面对对象高级编程

    面向对象高级编程: 面向对象编程:封装、继承和多态 面向对象高级编程:多重继承、定制类和元类

  • JS实现深度克隆

    一、概念 深度克隆:深度克隆的新对象可以完全脱离原对象,我们对新对象的修改不会反映到原对象中 二、知识点储备: 1...

  • js的面向对象

    面向对象:面向对象特点:抽象:抓住核心问题封装:只能通过对象来访问方法继承:从已有对象上继承出新的对象多态:多对象...

网友评论

      本文标题:面向对象-包装对象,继承,深度克隆

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