目录
克隆
arguments表示实参列表,是一个数组
浅层克隆
实现一个demo,不过因为是原始值,所以只是值拷贝
var obj = {
name : 'abc',
age : 123,
sex : 'female'
}
var obj1 = {
}
function clone(origin, target){
var target = target || {
};//防止没有target这种情况
for ( var prop in origin){
target[prop] = origin[prop];
}
return target;
}
clone(obj, obj1);
如果在obj中加入一个数组,那么在obj中就有了引用值,当这样克隆的时候,obj和obj1中的数组那个属性都指向一个地址
如何才能让克隆过来的引用值也拥有不同于之前的地址呢?就是让所有值都是相对独立的
思路:判断数据是引用值还是原始值,如果是原始值,就直接拷贝,如果是数组或对象这样的引用值,就创建一个对象用来放接下来的数据
浅拷贝es6中有一个语法糖,就是Object.assign(target, origin);
深层克隆
步骤:
最先是遍历全部对象 利用for in
1.判断是不是原始值(原始值直接拷贝)–利用typeof() --数组或者对象都会返回object
2.判断是数组还是对象 --instanceof、toString、constructor,建议使用toString
3.建立相应的数组或对象
4.递归重复上面的行为
代码如下
var obj = {
name : 'abc',
age : 123,
card : ['visa', 'master'],
wife : {
name : 'bcd',
son : {
name : 'aaa'
}
}
}
var obj1 = {
};
function deepClone(origin, target) {
var target = target || {
},
toStr = Object.prototype.toString,
arrStr = '[array Object]';
for (var prop in origin){
if (origin.hasOwnProperty(prop)) {
// 为了避免原型链上面的属性被copy
if(origin[prop] !== 'NULL' && typeof(origin[prop]) == 'object') {
// if (toStr.call(origin[prop]) == arrStr) {
// target[prop] = [];
// }else{
// target[prop] = {};
// }
// 用三目运算符来简化一下这个if else语句
target[prop] = toStr.call(origin[prop]) == arrStr ? [] : {
};
deepClone(origin[prop], target[prop]);
}else{
target[prop] = origin[prop];
}
}
}
return target;
}
这样就基本实现了所想要的功能,让两者相对独立,如图
三目运算符:条件判断 ? 表达式1 : 表达式2;
在条件成立的情况下,执行表达式1,否则执行表达式2
数组
数组实际上是一种特殊的对象
定义数组
-
定义数组自面量(推荐)
var arr = []; -
构造方法定义数组
var arr = new Array();
两种方法的区别:
分别用这两种方法,传入10
var arr = new Array(10);
var arr1 = [10];
构造方法里面传入一个数字,表达这个数组的长度,所以在构造方法里面,要注意不能传入小数
数组的读写
如果数组直接越界进行写入,前面未定义的会直接表示undefined,然后在想写入的那个地方写入数据,如果溢出读,会返回undefined,两者均不会报错
数组的常用方法
如果在函数里面传入负数,他会执行如下步骤
splice = function (pos){
pos += pos > 0 ? 0 : this.length;
}
改变原数组
- push()
在数组的最后添加数据(可以一次添加多个),然后返回数组的长度
自己实现一下push的功能,代码如下,在调用函数的时候,传进去的实参储存在arguments里面,this.length是在每一次循环的时候自动增长的
var arr = [1,2,3];
Array.prototype.push = function () {
for(var i = 0; i < arguments.length; i++){
this[this.length] = arguments[i];
console.log(this.length);
}
return this.length;
}
-
pop()
从数组的最后一位剪切,传入数据没用 -
shift()
从数组的最前面一位剪切,和pop差不多 -
unshift()
从数组的最前面开始加入数据,和push差不多 -
reverse()
把数组逆置,返回原数组 -
splice(从第几位开始, 截取多少的长度, 在切口处添加新的数据)
返回截取的部分 -
sort()
将数组里面的数字按升序排列,如果想要降序,在sort函数后面加上reverse函数(排序按照ASCII码来排序的,所以只能排字符)
// 规则:
// 1. 必须写两个形参
// 2. 看返回值 1) 当返回值为负数时,那么前面的数放在前面
// 2) 当返回值为正数时,后面的数在前
// 3) 为0时,不动
//类似冒泡排序的方法比较
var arr = [1, 2, 3, 9, 6, 4];
arr.sort(function (a, b) {
// if (a > b) {
// return 1;
// }else{
// return -1;
// }
return b - a;
// 两种结果一样
});
不能改变原数组
-
concat()
将两个数组拼接起来,成为一个全新的数组
arr.concat(arr1);表示把arr1拼接到arr后面,可以进行多个数组的拼接 -
toString()
就是把数组转变成字符串展示出来 -
slice(从该位开始截取,截取到该位)
不会改变原数组,如果是一个参数,那就是从第几位开始,一直截取到最后一位
不写就是全部截取 -
join()
括号里面传字符串,哪怕是传一个空串,返回一个以传入字符串为每个数之间的间隔的字符串,如果不传,就会默认以逗号相连,例如
-
split()
表示按照括号内的拆分,而且直接就让括号里面的内容消失,如下
类数组
和数组相似,但其实不是数组
类数组的要求:属性要为索引(数字)属性,必须要有length属性,最好加上push
var obj = {
"0" : 'a',
"1" : 'b',
"2" : 'c',
"length" : 3,
"push" : Array.prototype.push
}
展示一个题
var obj = {
"2" : 'a',
"3" : 'b',
"length" : 2,
"push" : Array.prototype.push
}
obj.push('c');
obj.push('d');
输出结果如图所示
可知length属性最为重要
分装type实现完全的typeof作用
function type(target){
var template = {
'[object Array]' : 'array',
"[object Object]" : "object",
"[object Number]" : "number - object",
"[object Boolean]" : "boolean - object",
"[object String]" : "string - object"
}
if (target == null){
return 'null';
}
if(typeof(target) == 'object'){
// 数组,对象,包装类
var str = Object.prototype.toString.call(target);
return template[str];
}else{
return typeof(target);
}
}
实现数组去重
// 方法一:
var arr = [1,1,1,1,3,3,3,5,5,5];
var arr1 = [];
function change(arr){
for(var i = 0; i < arr.length; i ++){
if (arr1.length == 0){
arr1.push(arr[i]);
}else{
var count = 0;
for( var j = 0 ; j < arr1.length ; j ++){
if (arr1[j] == arr[i] ){
count++;
}
}
if(count == 0){
arr1.push(arr[i]);
}
}
}
return arr1;
}
// 方法二:hash方法
Array.prototype.unique = function(){
var temp = {
},
arr = [],
len = this.length;//将this.length取出来是为了减少在后续多处使用this.length时的运算量
for (var i = 0; i < len; i ++){
if(!temp[this[i]]){
temp[this[i]] = 'abc';//这个值可以是其他,但是需要是非0的,因为在最前面判断的时候,需要一个非0的值来判断
arr.push(this[i]);
}
}
return arr;
}
hash利用了对象里面属性名不能重复的原理,当属性名不存在的时候,返回undefined
前面知识复习
-
一旦经历var的操作,所得出的属性叫做不可配置属性,不可配置属性delete不掉
-
undefined和null不能和数进行比较
-
形参的变量相当于var一个this
-
Object.creat(prototype, definedProperty),前一个变量是原型,后一个变量是特性,特性具体是些啥,还有待探究
-
func();相当于func.call();执行,在没有传入任何参数的时候,就是预编译的this指向
try…catch
用来找错误,将不确定是否正确的代码放入try中,如果出现错误,就会停止try中的代码的执行,然后继续执行外面的代码,这个过程不会报错,只会跳过try里面错误代码之后代码的执行,如果存在错误,那么catch就会将错误捕捉,catch里面传入的数据就相当于一个形参,她存在两个属性值,error.message和error.name,可以通过这两个属性找出代码的bug要注意的是,try…catch每次只能找到一处bug,因为在try执行的时候,遇到bug就终止执行try后面的部分了。
举个例子
try{
console.log('a');
console.log(b);
}catch(e){
console.log(e.name + ' ' + e.message);
}
console.log('try外面')
结果如图
对一些错误信息的了解
-
EvalError:eval()的定义和使用不一致
-
RangeError:数值越界
-
ReferenceError:非法或不能识别引用数值
-
SyntaxError:发生语法解析错误
-
TypeError:操作数类型错误
-
URIError:URI处理函数使用不当
ES5严格模式
现在普遍的使用是基于es3.0,配合es5.0的新增方法共同使用,当产生冲突的时候,会使用es3.0版本的
当启用es5.0严格模式,那么此时产生冲突的部分会遵循es5.0的使用
如何启用呢?
在逻辑块的最前面写上一行的代码,‘use strict’;一定得是字符串格式,这样就会启用es5.0严格模式
可以是这个script标签的逻辑最前面,也可以是在一个函数的逻辑最前面,实现局部启用es5.0严格模式
也就是说,这个启用,可以是全局的,也可以是局部的
es5严格模式一些要求
- 禁用with
with会改变作用域链,with里面填的对象会充当内部执行最近的作用域
因为更改作用域链会浪费效率,是一个大工程,所以在es5严格模式里面就把with给限制了
var obj = {
name : 'bcd'
}
function test() {
var name = 'abc';
with(obj){
console.log(name);
}
}
-
禁用arguments.callee,用于在立即执行函数里面执行递归
-
禁用func.caller,打印函数执行时所处的环境
-
赋值变量之前,必须进行声明
-
局部的this必须被赋值(赋值给什么就是什么)
-
拒绝重复属性和参数