-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 11.5 KB
/
content.json
1
[{"title":"Javascript的浅拷贝和深拷贝","date":"2018-02-28T02:17:18.000Z","path":"2018/02/28/Javascript的浅拷贝和深拷贝/","text":"为了更好的理解js的深浅拷贝,我们先来理解一些js基本的概念 —— Javascript有五种基本数据类型(也就是简单数据类型),它们分别是:Undefined,Null,Boolean,Number和String。还含有一种复杂的数据类型(也叫引用类型),就是对象 注意Undefined和Null的区别,Undefined类型只有一个值,就是undefined,Null类型也只有一个值,也就是null Undefined 其实就是已声明未赋值的变量输出的结果 null 其实就是一个不存在的对象的结果 1234var a;console.log(a)//undefinedconsole.log(document.getElementById('asdd'))//没有id为asdd的节点,输出null 基本数据类型与引用数据类型 1. 对于基本数据类型他们的值在内存中占据着固定大小的空间,并被保存在栈内存中。当一个变量向另一个变量复制基本类型的值,会创建这个值的副本,并且我们不能给基本数据类型的值添加属性 12345var x = 1;var y = x;x.name = 'hanna';console.log(y); //1console.log(x.name); //undefined 上面的代码中,x是基本数据类型(Number), y是x的一个副本,它们两者都占有不同位置但相等的内存空间,只是它们的值相等,若改变其中一方,另一方不会随之改变。 2. 对于引用类型复杂的数据类型即是引用类型,它的值是对象,保存在堆内存中,包含引用类型值的变量实际上包含的不是对象本身,而是一个指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针地址而已,因此两个变量最终都指向同一个对象 12345678var obj = { name:'Hanna Ding', age: 22}var obj2 = obj;obj2['c'] = 5;console.log(obj); //Object {name: "Hanna Ding", age: 22, c: 5}console.log(obj2); //Object {name: "Hanna Ding", age: 0, c: 5} 我们可以看到obj赋值给obj2后,但我们改变其中一个对象的属性值,两个对象都发生了改变,根本原因就是obj和obj2两个变量都指向同一个指针,赋值时只是复制了指针地址,它们指向同一个引用,所以当我们改变其中一个的值就会影响到另一个变量的值。 01 浅拷贝 其实上面那段代码就是浅拷贝,有时候我们只是想备份数组,但是只是简单让它赋给一个变量,改变其中一个,另外一个就紧跟着改变,但很多时候这不是我们想要的123456var arr = [1, 2, 3, '4'];var arr2 = arr;arr2[1] = "test"; console.log(arr); // [1, "test", 3, "4"]console.log(arr2); // [1, "test", 3, "4"] 02 深拷贝(1)数组对于数组我们可以使用slice() 和 concat() 方法来解决上面的问题 slice 12345var arr = ['a', 'b', 'c'];var arrCopy = arr.slice(0);arrCopy[0] = 'test'console.log(arr); // ["a", "b", "c"]console.log(arrCopy); // ["test", "b", "c"] concat 12345var arr = ['a', 'b', 'c'];var arrCopy = arr.concat(); //或者 [].concat(arr)arrCopy[0] = 'test'console.log(arr); // ["a", "b", "c"]console.log(arrCopy); // ["test", "b", "c"] 知识点补充: arrayObj.slice(start, [end]) 该方法返回一个 Array 对象,其中包含了 arrayObj 的指定部分。不会改变原数组arrayObj.concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。其实也就是下面这么个意思。。。但还是用上面的方法来实现比较简单高效些 function deepCopy(arr1, arr2) { for (var i = 0; i < arr1.length; ++i) { arr2[i] = arr1[i]; }} (2)对象对象的深拷贝实现原理: 定义一个新的对象,遍历源对象的属性 并 赋给新对象的属性 123456789101112var obj = { name:'Hanna Ding', age: 22}var obj2 = new Object();obj2.name = obj.name;obj2.age = obj.ageobj.name = 'xiaoDing';console.log(obj); //Object {name: "xiaoDing", age: 22}console.log(obj2); //Object {name: "Hanna Ding", age: 22} 理解了以上的基本思想,我们就可以封装一个方法 deepCopy来实现对象的深拷贝,代码如下 1234567891011121314151617181920var obj = { name: 'Hanna', age: 22}var deepCopy = function (source) { var result = {}; for(var key in source) { if(typeof source[key] === 'object') { result[key] = deepCopy(source[key]) } else { result[key] = source[key] } } return result;}var objCopy = deepCopy(obj)obj.name = 'ding';console.log(obj);//Object {name: "ding", age: 22}console.log(objCopy);//Object {name: "Hanna", age: 22} ES6中新增加了Object.assgin也可以实现对象的深拷贝 Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。 12345678910const object1 = { a: 1, b: 2, c: 3};const object2 = Object.assign({c: 4, d: 5}, object1);console.log(object2.c, object2.d);// expected output: 3 5","tags":[{"name":"javascript","slug":"javascript","permalink":"https://987763485.github.io/tags/javascript/"}]},{"title":"JavaScript常见的创建对象的几种方式","date":"2018-02-25T11:12:32.000Z","path":"2018/02/25/JavaScript常见的创建对象的几种方式/","text":"通过Object构造函数或对象字面量创建单个对象 这些方式有明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码。为了解决这个问题,出现了工厂模式。 工厂模式 考虑在ES中无法创建类(ES6前),开发人员发明了一种函数,用函数来封装以特定接口创建对象的细节。(实现起来是在一个函数内创建好对象,然后把对象返回)。 function createPerson(name,age,job){ var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ alert(this.name); }; return 0;} var person1=createPerson(“Nicholas”,29,”Software Engineer”);var person2=createPerson(“Greg”,27,”Doctor”); 函数createPerson()能够根据接受的参数来构建一个包含所有必要信息的Person对象。工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题,即怎么知道一个对象的类型。随着JS发展,又一个模式出现了。 构造函数模式 像Object和Array这样的原生构造函数,在运行时会自动出现在执行环境。此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。 function Person(name,age,job){ this.name=name; this.age=age; this.job=job; this.sayName=function(){ alert(this.name); };} var person1=new Person(…);var person2=new Person(…); 与工厂模式相比,具有以下特点:没有显式创建对象;直接将属性和方法赋给了this对象;没有return语句;要创建新实例,必须使用new操作符;(否则属性和方法将会被添加到window对象)可以使用instanceof操作符检测对象类型 构造函数的问题: 构造函数内部的方法会被重复创建,不同实例内的同名函数是不相等的。可通过将方法移到构造函数外部解决这一问题,但面临新问题:封装性不好。 这些问题可通过原型模式解决。 原型模式 我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。(prototype就是通过调用构造函数而创建的那个对象实例的原型对象)。 使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。 function Person(){} Person.prototype.name=”Nicholas”;Person.prototype.age=29;Person.prototype.job=”…”;Person.prototype.sayName=function(){ …}; var person1=new Person();person1.sayName();//“Nicholas” 更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象,并重设constructor属性。 function Person(){} Person.prototype={ name:”…”, age:29, job:”…”, sayName:function(){ … }}; Object.defineProperty(Person.prototype,”constructor”,{ enumerable:false, value:Person,}); 原型对象的问题:他省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值,虽然这会在一定程度带来一定的不便,但不是最大的问题,最大的问题是由其共享的本性所决定的。对于包含基本值的属性可以通过在实例上添加一个同名属性隐藏原型中的属性。然后,对于包含引用数据类型的值来说,会导致问题。 这些问题导致很少单独使用原型模式。 组合使用构造函数模式和原型模式 这是创建自定义类型的最常见的方式。 构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。所以每个实例都会有自己的一份实例属性的副本,但同时共享着对方法的引用,最大限度的节省了内存。同时支持向构造函数传递参数。 function Person(name,age,job){ this.name=name; this.age=age; this.job=job; this.friends=[“S”,”C”];} Person.prototype={ constructor:Person, sayName:function(){ alert(this.name); }}; var person1=new Person(…); 动态原型模式function Person(name,age,job){ this.name=name; this.age=age; this.job=job; if(typeof this.sayName!="function"){ Person.prototype.sayName=function(){ alert(this.name); }; } } 这里只有sayName()不存在的情况下,才会将它添加到原型中,这段代码只会在初次调用构造函数时才执行。这里对原型所做的修改,能够立刻在所有实例中得到反映。 Object.create() ES5定义了一个名为Object.create()的方法,它创建一个新对象,其中第一个参数是这个对象的原型,第二个参数对对象的属性进行进一步描述。 另有寄生构造函数模式和稳妥构造函数模式原文链接:https://www.cnblogs.com/zczhangcui/p/6389023.html","tags":[{"name":"javascript","slug":"javascript","permalink":"https://987763485.github.io/tags/javascript/"}]},{"title":"国内知名前端团队","date":"2018-02-22T11:24:44.000Z","path":"2018/02/22/国内知名前端团队/","text":"腾讯 腾讯IMWEB 腾讯AlloyTeam 腾讯CDC 阿里 淘宝前端团队FED 京东 凹凸实验室 京东设计中心JDC 百度 百度Fex 百度efe 百度eux 360奇舞团 奇虎360 去哪儿 去哪大前端YMFE 携程 携程UED 美团 美团前端 有赞 有赞技术团队 人人网 人人Fed 滴滴出行 滴滴开源平台 字节跳动 字节跳动技术博客 其他 印记中文 deepOcean 优优设计网 国内顶尖团队的开源地址 前端资源整合","tags":[{"name":"web前端","slug":"web前端","permalink":"https://987763485.github.io/tags/web前端/"}]},{"title":"开篇","date":"2018-02-19T11:04:57.000Z","path":"2018/02/19/开篇/","text":"今天开通了GitHub博客,希望在以后的日子里能记录在编程中遇到的问题,以便学习!","tags":[]}]