web前端开发笔记整理(六)

JavaScript对象克隆

浅拷贝

浅拷贝引用值是要相互影响的,因为它是栈内存之间的赋值,赋值的是地址,一个更改,其他的都要更改。

var obj = {
        name :'abc',
        age  : 123,
        sex : 'female',
        card : ['visa','master']//存在一个引用值
    }
    var obj1 = {}
    function clone(origin,target) {
        var target = target || {};//防止没有提前新建一个空对象
        for(var prop in origin){
            target[prop] = origin[prop];
        }
    }
    clone(obj,obj1);

深度拷贝

深拷贝就是无论是原始值还是引用值,修改后彼此相互不影响。
遍历对象 for(var prop in obj)(for in也可以遍历数组(数组也是特殊类型的对象))
1,判断是不是原始值 typeof() object—>引用值
2,判断是数组还是对象 constructor,instanceof,toString
3,建立相应的数组或者对象
4,递归

// JavaScript Document
var obj = {
        name :'abc',
        age  : 123,
        sex : 'female',
        card : ['visa','master']//存在一个引用值
    }
    var obj1 = {}

function deepClone(origin, target){
    var target = target || {},
        toStr = Object.prototype.toString,
        arrStr = "[Object Array]";

        for(var prop in origin){  
            if(origin.hasOwnProperty(prop)){
                if(origin[prop] !== "null" && typeof(origin[prop]) == 'object'){

                //    if(toStr.call(origin[prop]) == arrStr){
                //        target[prop] = [];
                //    }else{
                //     target[prop] = {};
                //    }   
                //上面的ifelse条件判断可以用下面的三目运算符代替: 
                target[prop] = toStr.call(origin[prop]) == arrStr ? [] : {};
                deepClone(origin[prop],target[prop]);  
                
                }else{
                    target[prop] = origin[prop];
                }
            }
        }
        return target;
}
deepClone(obj,obj1);

在这里插入图片描述
更改引用值之间相互不影响
在这里插入图片描述

数组

数组的两种创建方式

  • var arr = [];//字面量(内部还是new Array()的方式)

  • var arr = new Array();

改变原数组方法

  • push()

功能:在数组的最后一位新增一个或多个数据,并且返回新数组的长度,会改变原来的数组
注意:push()方法返回的是数据是新数组的长度,它增加的数据可以是一个也可以是多个,可以理解为增加一连串的数据

在这里插入图片描述在这里插入图片描述

模拟系统调用数组的push方法:
Array.prototype.push = function(){
    for(var i = 0; i <arguments.length; i++){
        this[this.length] = arguments[i];
    }
    return this.length;
}
  • pop()

功能:删除数组的最后一位,并且返回删除的数据,会改变原来的数组
注意:带了参数也没得用,还是删除最后一个
在这里插入图片描述

  • shift()

功能:删除数组的第一位数据,并且返回新数组的长度,会改变原来的数组
在这里插入图片描述
带不带参数都是一样的,只剪切数组的第一个元素

在这里插入图片描述

  • unshift

在数组的第一位添加元素。返回的是数组的长度
在这里插入图片描述

  • sort
    数组直接调用sort()方法,它是 按照ASCII排序的。

ASCII比较大小的时候,是比较两个数中的第一个字符。

  • 常见ASCII码的大小规则,0-9<A-Z<a-z:
  • 数字比字母要小。如 “7”<“F”
  • 数字0比数字9要小,并按0到9顺序递增。如 “3”<“8”
  • 字母A比字母Z要小,并按A到Z顺序递增。如“A”<“Z”
  • 同个字母的大写字母比小写字母要小32。如“A”<“a”

记住几个常见字母的ASCII码大小: “A”为65;“a”为97;“0”为48;
在这里插入图片描述

让数组按照大小排序就要实现sort高阶函数的使用
1,必须写两个形参
2,看返回值
1)当返回值为负数时,那么前面的是放在前面
2)当返回值为正数时,那么后面的是放在前面
3)为0,不动

var arr= [1,3,5,4,10];
arr.sort(function (a,b) {
   if(a > b){
       return 1;
   }else{
       return -1;
   }
});
console.log(arr);//[1,3,4,5,10]

上面高阶sort函数的实现可以简化为下面这种形式:

arr.sort(function (a,b) {
  return a-b;//升序
//  return b-a;//降序
});

它是这样的执行过程,数组里面的数首先传a= 1,b = 3,1和3比,然后1,4。1,5。1,10 。3,4。3,5 。3,10 。4,5 。4,10 。5,10 。

这样多次调用里面的函数进行比较(就想冒泡排序一样)

因为 if(a > b){return 1;}就可以为 if(a - b > 0){return 1;}—>return a - b

因为这个时候a> b,只要返回整数就可以了

然后再else里面就是a<b返回负数,那么return a-b肯定是负数。所有它们都返回的是a-b,直接一下子就返回a - b

给一个有序的数组排序,让它每一次执行都是乱序

var arr = [1,2,3,4,5,6,7];
arr.sort(function () {
   return Math.random() - 0.5;
});


console.log(arr);
  • 发现每执行一次,arr数组里面的顺序都不一样。

  • 因为 Math.random()返回的结果是(0,1),这样减去0.5,那么它有为正的概率和为负的概率是一半一半。

  • 根据sort函数的原理,如果返回的是正数,那么后面的和前面的调个位置,如果返回的是负数或者0,那么前面的还是在前面

将数组里面的按字节长度排序

var arr = ['ac','nsfauigf','网络','osy题词','wdfewfef','addasd'];
function retBytes(str) {
    var num = str.length;
    for(var i = 0; i <str.length; i++){
        if(str.charCodeAt(i) > 255){
            num++;
        }
    }
    return num;
}
arr.sort(function(a,b) {
    return retBytes(a) - retBytes(b);
})
  • reverse

数组反转
在这里插入图片描述

  • splice

splice ( 从第几位开始截取 , 截取多少位 , 在截取点处添加什么)
在这里插入图片描述

在这里插入图片描述

负数的实现原理是这样的:pos += pos > 0 ? 0 : this.length;也就是倒数的第几位
首先判断,如果是负数的话那就是负数加上长度就等于正数的第几位(从0开始)
在这里插入图片描述

不改变原数组方法

  • concat
var arr = [1,2,3]
var arr1 = [4,5,6]
var arr3 = arr.concat(arr1);//arr3 : [ 1, 2, 3, 4, 5, 6 ]

例题:
把这一串字符串链接起来,不用+号的方式(因为字符串是原始值,存在栈内存里面的,这样来回在栈内取元素很浪费时间。 )。

var str1 = "nsd";
var str2 = "sdsfd";
var str3 = "fadf";
var arr = [str1,str3];//数组是散列结构
console.log(arr.join(""));//nsdfadf
//console.log(arr.join());// nsd,fadf

join()里面为空就是用逗号连起来。

数组的方法join 和 字符串的方法split是互逆的

var arr= [1,2,3,4,5]; 
var str = arr.join("-"); // "1-2-3-4-5"
var shuzu =str.split("-");//[ "1", "2", "3", "4", "5" ]
  • toString
var arr = [1,2,3,4]
console.log(arr.toString());//1,2,3,4
  • slice

返回值是截取的值,不改变原数组。

  • slice两个参数(从该位为开始截取,截取到该位)

  • slice一个参数(从该位开始截取到后面所有都截取)

  • slice没有参数(整个截取)
    在这里插入图片描述
    在这里插入图片描述

类数组

  • 可以利用属性名模拟数组的特性
  • 可以动态的增加length属性
  • 如果强行让类数组调用push方法,则会根据length属性值的位置进行属性值的扩充。
    类数组举例

1,arguments
2,一个对象:属性要为索引(数字)属性,必须有length属性,最好加上push

类数组里面最关键的是length属性,类数组中push实现的原理

Array.prototype.push = function (target) { 
    obj[obj.length] = target;
    obj.length++;
}
var obj = {
    "2" : "a",
    "3" : "b",
    "length" : 2,
    "push" : Array.prototype.push
}
obj.push('c');
obj.push('d');
console.log(obj);
//Object { 2: "c", 3: "d", length: 4, push: push() }
var obj = {
    "1" : "a",
    "2" : "c",
    "3" : "d",
    "length" : 3,
    "push" : Array.prototype.push
}
obj.push('b');
console.log(obj);
//Object { 1: "a", 2: "c", 3: "b", length: 4, push: push() }
var obj = {
    "0" : 'a',
    "1" : 'b',
    "2" : 'c',
    name :"abc",
    age  : 123,
    length : 3,
    push : Array.prototype.push,
    splice :Array.prototype.splice
}

类数组的好处就是把数组和对象的好处拼到一起,
但是并不是所有的数组方法都能用,除非你自己添加

封装typeof方法

1,分两类,原始值和引用值
2.区分引用值

function type (target){  
    var ret = typeof(target);
    var template = {
        "[object Array]" : "array",
        "[object Object]" : "object",
        "[object Number]" : "number-object",
        "[object String]" : "string-object",
        "[object Boolean]" : "boolean-object"
    }
    if(target === null){
        return "null";
    }else if(ret == 'object'){//引用值:数组,对象,包装类
     var str = Object.prototype.toString.call(target);
        return template[str];//属性值
    }else{
        return ret;//原始值:直接用typeof来区分
    }
}

数组去重(要求在原型链上编程)

var arr = [1,1,1,1,2,2,2,2,2];
//利用对象的一个属性只能对应一个值的特性来去重
//var obj = {
//    "1" : 'abc',
//    "2" : 'abc,
//}
"1"-->undefined
"1"-->"abc"
"2"-->undefined
"2"-->"abc"

//新建一个对象,遍历数组里面的每一个值拿来当做对象的一个属性,如果该属性已经存在了值,那就跳过,继续找下一个值。
//看它是不是为对象在对象里面已经有了值,如果没有值,那就把数组里面的这个值作为该对象的一个新的属性。
//最后输出对象的所有属性就是去掉数组里面重复的值。

Array.prototype.unique = function () {
    var temp = {};					//新建一个空对象
    var arr = []; 					//新建一个空数组,用来返回 去重后的结果 
    var len = this.length;
    for(var i = 0; i < len; i++){
        if (!temp[this[i]] ) { 		//this[i]表示arr[i]表示数组里面的每一个值
     							   //temp[this[i]]表示对象里面的这个属性(数组里面的值)的值是不是undefined,如果是undefined,就说明这要添加到该对象里面为一个新的属性。
     							   //所以这个地方就是!temp[this[i]],表述如果它是!undefined == true就要给它赋值,然后push到去重数组里面去。
            temp[this[i]] = 'abc';
            arr.push(this[i]);
        }
    }
    return arr;
}

ES5严格模式

Javascript 的保留关键字不可以用作变量、标签或者函数名。有些保留关键字是作为 Javascript 以后扩展使用。ES5较ES3新添加了几个保留关键字:

1)class:类,ES6引入
2)const:常量,ES6引入
3)enum:枚举类型
4)extends:类继承,ES6引入
5)import:模块导入,ES6引入
6)export:模块导出,ES6引入
7)super:调用父类的构造函数,ES6引入
浏览器兼容性

1)ES3,可以认为所有浏览器都支持;
2)ES5,现代浏览器都支持(>=IE9), IE9不支持严格模式。

在try里面的发生错误,不会执行错误后的try里面的代码

  • try 测试代码块的错误。
  • catch 语句处理错误。
  • throw 创建并跑出错误。
try
   {
   //在这里运行代码
     抛出错误
   }
 catch(err)
   {
   //在这里处理错误
   }

请输出一个 5 到 10 之间的数字:

<input id="demo" type="text">
<button type="button" onclick="myFunction()">测试输入</button>
<p id="mess"></p>

</body>
</html>
<script type="text/javascript">
    function myFunction(){
    try{ 
        var x=document.getElementById("demo").value;   取元素的值
        
        if(x=="")    throw "值为空";       根据获取的值,抛出错误
        if(isNaN(x)) throw "不是数字";
        if(x>10)     throw "太大";
        if(x<5)      throw "太小";
    }
    catch(err){
        var y=document.getElementById("mess");     抓住上面throw抛出的错误,给p标签显示
        y.innerHTML="错误:" + err + "。";
    }
}
</script>

Error.name的六种值对应的信息

  • EvalError : eval()的使用与定义不一致

  • RangeError : 数组越界

  • ReferenceError : 非法或不能识别的引用数值(一般没有定义就使用就会报ReferenceError)

  • SyntaxError :发生语法解析错误

  • TypeError : 操作数类型错误

  • URIError : URI处理函数使用不当

es5.0严格模式

启动es5.0的严格模式用"use strict" ,放在逻辑的最顶端(全局严格模式),或者放在局部的最顶端让它部分启用es5.0的严格模式(局部函数内的严格模式)。

这个时候和es3.0产生冲突的部分全部使用es5.0的严格模式

"use strict"就是一行字符串。不会对不兼容严格模式的浏览器产生影响

不支持with,arguments.callee,function.caller

 var obj={
     name:"obj"
 }
 var name='window';
 function test(){
     var name="scope";
     with(obj){
         console.log(name);
    }
 }
 test()

with它会改变作用域链,with(obj)里面跟的obj会被放在作用域的最顶端,那么首先查找作用域链的时候就会找obj里面的。因为with的功能太强大,消耗大量的资源。所以在严格模式里面不准用

变量赋值前必须声明。
  var a = b = 3;//会报错,b报错

局部this必须被赋值(Person.call(null/undefined)赋值什么就是什么) ,就是说预编译this不再指向window,它为undefined,在全局范围里面this依旧是指向window。

es5拒绝重复的属性 和参数
eval是魔鬼
eval 能该表作用域

数组去重

第一种方法用ES6里面的Set特性来去重

var arr = [4,7,9,4,7,8,9,4];
        var set = new Set();
        for(var i = 0; i< arr.length; i++){
            set.add(arr[i]);
        }
        console.log(set);

第二种方法用一个新的数组里面indexOf属型的性质来去重
(indexOf返回的就是字符出现在字符串的位置,或者判断字符串出现在数组的位置,返回数组的下标)

   var newArr=[];
    for(var i = 0; i < arr.length; i++){
        if(newArr.indexOf(arr[i]) == -1){
            newArr.push(arr[i]);
        }
    }
    console.log(newArr);

第三种方法就一句就可以实现去重

  console.log(Array.from(new Set(arr)));

寻找落单

第一种方法:用ES6里面的Set去重留下落单的那个。

var arr = [1,2,3,4,5,1,2,3,4];
        var set = new Set();
        for(var i = 0; i <arr.length; i++){
            if(set.has(arr[i])){
                set.delete(arr[i]);
            }else{
                set.add(arr[i]);
            }
        }
        console.log(set);//结构是一个数组:   Set(1) {5}
        console.log(...set);//5  用展开运算符把数组展开

第二种方法:根据对象的属性是不允许有重复的这一特性。

var arr = [1,2,3,4,5,1,2,3,4];
        var obj = {};
        for(var i  = 0; i < arr.length; i++){
            if(obj[arr[i]]){
                delete obj[arr[i]];
            }else{
                obj[arr[i]] = true;
            }
        }
        console.log(Object.keys(obj)[0]);//通过这种方法拿到对象的key

第三种方法用到了异或^
首先你要知道0和任何数异或都等于任何数,然后任何数和自己异或都为0,
因为相同为0,不同为1,它也存在交换律和结合律。
所以用它在找那个落单的数,是一定可以找到的。

var arr = [1,2,3,4,5,1,2,3,4];
        var result = 0
        for(var i  = 0; i < arr.length; i++){
            result ^=arr[i];
        }
        console.log(result);

在这里插入图片描述

原创文章 106 获赞 369 访问量 9万+

猜你喜欢

转载自blog.csdn.net/Miracle1203/article/details/105846006