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

包装对象

为什么字符串,数字等基础类型是没有属性和方法的。那么我们平时创建了一个字符串(非字符串对象)的时候,为什么可以调用他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值的深度克隆

以上!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容