最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript 进阶技能,中高级前端必备|8月更文挑战

    正文概述 掘金(代码搬运媛)   2021-08-19   558

    创建对象的三种方式

    对象字面量

    对象名 = {}
    
    var obj = {
    	name : '张三',
        age : 20,
        say : function () {
            console.log('say...');
        }
    }
    

    系统构造函数,工厂模式

    对象名 = new Object();
    
    function createObject (name,age) {
    	var obj = new Object();
        obj.name = name;
        obj.age = age;
        obj.say = function () {
            console.log('say....');
        }
    }
    

    自定义构造函数

    原理同工厂模式,方法名首字母大写。自定义构造函数自动做了四件事:

    a: 在内存中创建新的对象

    b: this 指向这个对象

    c: 给这个对象添加属性和方法

    d: 返回这个新对象

    function Person (name,age) {
        this.name = name;
        this.age = age;
        this.say = function () {
            console.log('say...');
        }
    }
    

    检测对象是否是某个构造函数实例化的结果

    (1)对象.instanceof.构造方法

    (2)对象.constructor == 构造方法

    工厂模式创建对象与构造函数创建对象的区别

    工厂模式:

    函数名小驼峰命名法,函数内部有new,返回值为所创建对象。直接调用函数创建对象。实例对象的构造类都是Object,不方便区分是哪一类。

    构造函数:

    函数名大驼峰命名法,函数内部没有new,没有返回值,this代指当前对象,通过new的方式创建对象。方便区分是某类的对象,可以用instanceof检测

    构造函数与实例对象的区别

    function Person(name, age, sex){    
        this.name = name;    
        this.age = age;    
        this.sex = sex;    
        this.say = function(){        
            console.log("say....");    
        }; 
    }
    var p = new Person("aa", 13, "男"); 
    //构造函数与实例对象之间的关系 
    //实例对象是通过构造函数创建出来的 
    //console.dir打印对象结构 
    console.dir(p); 
    //打印实例对象 
    console.dir(Person); 
    //打印构造函数
    //constructor实例对象的构造器 指向的是Person 所以这个实例对象是通过Person来创建的 
    console.log(p.__proto__.constructor == Person.prototype.constructor); console.log(p.constructor == Person);
    

    结论:

    实例对象是通过构造函数创建的 可以通过 实例对象.构造器 == 构造函数名 来判断对象是不是这个构造函数创建的 对象 instanceof 构造函数名 一般使用这种方式

    原型

    原型的引入

    //构造函数  构造函数名Person
    function Person(name, age){
        this.name = name;
        this.age = age;
        this.say = function(){
            console.log("say");
        };
    }
    //得到一个实例对象
    var p1 = new Person("aa", 34);
    var p2 = new Person("bb", 45);
    //这两个方法是否是同一个方法? 不是同一个方法
    p1.say();
    p2.say();
    

    结论:

    通过上述方式创建的对象,分别拥有自己的属性和方法。如果多个实例对象拥有同样的方法,采用这种方式比较浪费空间,可以采用原型对象的方式,将共有的属性和方法存储在原型对象中,实现空间共享,节省空间。

    原型的作用

    数据共享

    在构造函数中定义的属性和方法,在实例对象的时候,实例对象的属性和方法都是在自己的空间中存在的。如果实例化多个对象,那么这些属性和方法都会存储在单独的空间,为了节省内存空间,我们会把对象共有的属性或方法写在原型对象中,实现节省内存空间。

    改变this指向

    原型对象中的this指向为实例对象,指向可以改变。

    构造函数、实例、原型之间的关系

    Javascript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。 这个对象的所有属性和方法,都会被构造函数的实例继承。 这也就意味着,我们可以把所有对象实例需要共享的属性和方法直接定义在 prototype 对象上。

    这时所有实例的 type 属性和 sayName() 方法, 其实都是同一个内存地址,指向 prototype 对象,因此就提高了运行效率。

    任何函数都具有一个 prototype 属性,该属性是一个对象。

    通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针 proto

    总结: 任何函数都具有一个 prototype 属性,该属性是一个对象 构造函数的 prototype 对象默认都有一个 constructor 属性,指向 prototype 对象所在函数 通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针 proto 所有实例都直接或间接继承了原型对象的成员

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GkotGMpW-1577673827666)(/home/yujing/.config/Typora/typora-user-images/image-20191119103004205.png)]

    通过原型对象添加方法

    //构造函数  构造函数名Person
    function Person(name, age){
    this.name = name;
    this.age = age;
    }
    
    //使用原型添加方法
    Person.prototype.say = function(){
    	console.log("say....");
    };
    
    //判断两个方法是否是同一个方法
    console.log(p1.say == p2.say); //true
    

    结论:

    使用原型对象创建属性和方法,在实例化对象中看不到这个属性或方法。

    原型对象

    实例对象中有一个__proto__的属性,就是原型,也是一个对象,这个属性是给浏览器使用,不是标准属性,__proto__可以叫原型对象

    构造函数中有一个prototype的属性,就是原型,也是一个对象,这个是标准属性,这个属性是程序使用的。prototype可以叫原型对象

    实例对象中的__proto__属性与构造函数中的prototype属性相等

    实例对象是通过构造函数创建出来的,构造函数中有prototype原型对象

    实例对象__proto__指向了构造函数中的原型对象

    通过原型添加属性和方法

    Person.prototype.classid = "220";
    Person.prototype.eat = function(){
    	console.log("吃盒饭.....");
    };
    Person.prototype.study = function(){
    	console.log("吃饭睡觉打豆豆,就是不学习,因为我不学就会");
    };
    

    以上代码可以简写:

    需要注意的是,需要手动添加 constructor 构造器

    //使用原型添加属性和方法
    Person.prototype = {
        //手动添加构造器
        constructor: Person,
        classid: "220",
        eat: function(){
            console.log("吃饭的方法");
        }
    };
    

    总结:实例对象与原型对象的关系

    构造函数可以实例化对象。

    构造函数中有一个属性叫prototype,是构造函数的原型对象。

    构造函数的原型对象(prototype)中有一个constructor构造器,这个构造器指向的就是自己所在的原型对象所在的构造函数。

    实例对象的原型对象(proto)指向的是该构造函数的原型对象。

    实例对象属性与原型属性重名问题

    当访问实例对象的某个属性的时候,首先会在实例对象的构造函数中寻找,找到了就直接使用,找不到就会按照原型链向原型对象中寻找。如果找不到,属性会返回 undefined 方法会返回 not a function

    通过实例对象可以改变原型对象中的属性值吗?

    不可以。如果想改变原型对象中属性的值,可以直接通过 原型对象.属性 = 值 的方式改变。

    原型对象使用建议

    私有成员(一般就是非函数成员)放到构造函数中 共享成员(一般就是函数)放到原型对象中 如果重置了 prototype 记得修正 constructor 的指向

    可以为系统内置对象添加原型方法,相当于再改源码

    String.prototype.myReverse=function () {      
        for(var i=this.length-1;i>=0;i--){        
            console.log(this[i]);      
        }    
    };    
    var str="abcdefg";    
    str.myReverse();
    

    构造函数与实例对象的关系

    • 实例对象是由构造函数所创建的;

    • 实例对象中的 proto 中的 constructor指向构造函数 构造函数中的 constructor存储构造函数本身

    验证一个实例对象是否是由某个构造函数产生的

    ​ 对象 instanceof 构造方法 判断 建议用这个 ​ 对象.constructor = 构造方法名 返回布尔值

    原型中的方法是可以互相访问的

    function Animal(name,age) {      
        this.name=name;      
        this.age=age;    
    }    
    //原型中添加方法    
    Animal.prototype.eat=function () {      
        console.log("动物吃东西");      
        this.play();    
    };    
    Animal.prototype.play=function () {      
        console.log("玩球");      
        this.sleep();    
    };    
    Animal.prototype.sleep=function () {      
        console.log("睡觉了");
    }
    

    注意:

    实例化对象与原型属性重名时,先寻找对象本身的属性,对象本身没有时再采用原型的属性,都没有时属性返回undefined,方法返回not a function

    function Person(age,sex) {     
        this.age=age;//年龄     
        this.sex=sex;     
        this.eat=function () {      
            console.log("构造函数中的吃");    
            };   
    }   
    Person.prototype.sex="女";   
    Person.prototype.eat=function () {    
    	console.log("原型对象中的吃");   
    };   
    var per=new Person(20,"男");   
    console.log(per.sex);  //男 
    per.eat();//构造函数中的吃
    

    原型链

    原型链:是一种关系,实例对象和原型对象之间的关系,他们的关系 是通过原型 __ proto__ 来联系的。 每个构造函数都有一个 prototype 属性,每个实例对象都有一个 __ proto__ 属性,而 __ proto__ 属性指向构造函数的 prototype 属性。按照__ proto__ 寻找原型链的构造函数,会发现实例对象的顶端是 Object ,再向上寻找__ proto__ 会返回null。

    //构造函数 
    function Person(name,age) {  
        //属性  
        this.name=name;  
        this.age=age;  
        //在构造函数中的方法  
        this.eat=function () {    
            console.log("吃吃吃");  
        }; 
    } 
    //添加共享的属性 
    Person.prototype.sex="男"; 
    //添加共享的方法 
    Person.prototype.sayHi=function () {  
        console.log("您好啊,"); };
    //实例化对象,并初始化 
    var per=new Person("小明",20); 
    per.sayHi(); 
    //如果想要使用一些属性和方法,并且属性的值在每个对象中都是一样的,方法在每个对象中的操作也都是一 样,那么,为了共享数据,节省内存空间,是可以把属性和方法通过原型的方式进行赋值
    console.dir(per);
    //实例对象的结构 
    console.dir(Person);
    //构造函数的结构
    //实例对象的原型__proto__和构造函数的原型prototype指向是相同的
    //实例对象中的__proto__原型指向的是构造函数中的原型prototype 
    console.log(per.__proto__==Person.prototype); 
    //实例对象中__proto__是原型,浏览器使用的 //构造函数中的prototype是原型,程序员使用的
    

    原型的指向是可以改变的

    实例对象的原型 __ proto __ 指向的是该对象所在的构造函数的原型对象。如果构造函数的原型对象 prototype 指向发生了改变,实例对象的原型 __ proto__ 指向也会发生改变。实例对象和原型对象之间是通过 __ proto__ 原先来联系的,这个关系就是原型链。

    //人的构造函数 
    function Person(age) {  
        this.age=10; 
    } 
    //人的原型对象方法 
    Person.prototype.eat=function () {  
        console.log("人的吃"); 
    }; 
    //学生的构造函数 
    function Student() {
        } 
    Student.prototype.sayHi=function () {  
        console.log("嗨,小苏你好帅哦"); 
    }; 
    //学生的原型,指向了一个人的实例对象 
    Student.prototype=new Person(10); //改变了原型的指向
    var stu=new Student(); 
    stu.eat(); stu.sayHi();
    
    

    原型的最终指向问题

    Javascript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。 这个对象的所有属性和方法,都会被构造函数的实例继承。 这也就意味着,我们可以把所有对象实例需要共享的属性和方法直接定义在 prototype 对象上。 prototype是对象,所以prototype这个对象中也有 proto ,指向了哪儿里?(对象中 proto 指 向的都是构造函数的prototype) 所以prototype这个对象中的 proto 指向的应该是某个构造函数的原型prototype

    function Person() { 
    } 
    Person.prototype.eat=function () {  
        console.log("吃东西"); 
    };
    var per=new Person(); 
    console.dir(per); 
    console.dir(Person); 
    
    //per实例对象的__proto__------->Person.prototype的__proto__---->Object.prototype的 __proto__是null
    console.log(per.__proto__==Person.prototype); console.log(per.__proto__.__proto__==Person.prototype.__proto__); console.log(Person.prototype.__proto__==Object.prototype); console.log(Object.prototype.__proto__);
    

    原型指向改变如何添加方法

    如果原型的指向发生改变,那么应该在原型改变指向之后再添加原型方法。

    //人的构造函数 
    function Person(age) { 
        this.age=age; 
    } 
    //人的原型中添加方法 
    Person.prototype.eat=function () { 
        console.log("正在吃东西"); 
    }; 
    //学生构造函数 
    function Student(sex) { 
        this.sex=sex; 
    } 
    //改变了原型对象的指向  
    Student.prototype=new Person(10);
    //学生的原型中添加方法----先在原型中添加方法  
    Student.prototype.sayHi=function () {  
        console.log("哈喽哈喽");  
    };  
    var stu=new Student("男");  
    stu.eat();  
    stu.sayHi();
    console.dir(stu);
    

    继承

    JS 不是一门面向对象的语言,它是一门基于对象的语言。我们学习 JS 的面向对象,是英文面向对象的思想适合人的想法,编程会更加方便,也利于后期的维护。

    继承:首先继承是一种关系。

    可以通过构造函数模拟类,然后通过改变原型指向来实现继承。继承也是为了实现数据共享。

    缺陷:通过改变原型指向实现的继承,直接初始化了属性,继承过来的属性的值都是一样的。为了解决这一个问题,我们可以使用 call 函数。(指构造函数中的属性值不能改变)

    继承的时候,可以不改变原型的指向,直接调用父级的构造函数的方式来为属性赋值就可以了。借用构造函数,把要继承的父级的构造函数拿过来,使用一下就可以了。

    要借用的构造函数.call(要绑定函数的对象 [, 函数的参数1] [, 函数的参数2....] )

    缺陷:父级中的方法不能继承。(指原型对象中的成员不能继承)

    所以,为了完美实现继承,我们采用 原型继承 + 借用构造函数 来实现继承。

    原型继承 + 借用构造函数 来实现继承

    function Person(name,age,sex) {  
        this.name=name;  
        this.age=age;  
        this.sex=sex; 
    } 
    Person.prototype.sayHi=function () {  
        console.log("哈喽"); 
    }; 
    function Student(name,age,sex,score) {  
        //借用构造函数:属性值重复的问题  
        Person.call(this,name,age,sex);  
        this.score=score; 
    } 
    //改变原型指向----继承 
    Student.prototype=new Person();
    //不传值 //改变原型指向后添加方法 
    Student.prototype.eat=function () {  
        console.log("吃东西"); 
    }; 
    var stu=new Student("小黑",20,"男","100分"); console.log(stu.name,stu.age,stu.sex,stu.score); 
    stu.sayHi(); 
    stu.eat(); 
    var stu2=new Student("小黑黑",200,"男人","1010分"); console.log(stu2.name,stu2.age,stu2.sex,stu2.score); 
    stu2.sayHi(); 
    stu2.eat();
    

    拷贝继承

    把一个对象的竖向或方法通过遍历对象 直接复制到另一个对象中。

    function Person() {} 
    Person.prototype.age=10; 
    Person.prototype.sex="男"; 
    Person.prototype.height=100; 
    Person.prototype.play=function () { 
        console.log("玩的好开心"); 
    }; 
    var obj2={}; 
    //Person的构造中有原型prototype,prototype就是一个对象,那么里面,age,sex,height,play都是 该对象中的属性或者方法 
    for(var key in Person.prototype){ 
        obj2[key]=Person.prototype[key]; 
    } 
    console.dir(obj2); 
    obj2.play();
    

    总结继承:

    原型继承:改变原型的指向

    借用构造函数继承:主要解决属性值不可改变的问题

    原型继承 + 借用函数继承,既能解决属性的问题,又能解决方法继承的问题。

    拷贝继承:就是把对象中需要共享的属性或方法,通过遍历的方式复制到另一个对象中。

    函数

    函数声明和函数表达式的区别:

    函数声明如果放在 if... else 分支结构中,在IE8 中会出现问题

    //函数声明方式
    if(true){    
        function f1() {        
            console.log("真区间函数");    
        } 
    }else{
        function f1() {        
            console.log("假区间函数");    
        } 
    } 
    f1();//IE8 下返回 ‘假区间函数’
    
    
    //函数表达式方式
    var f2; 
    if(true){    
        f2=function () {    
            console.log("函数表达式--真区间");    
        }; 
    }else{    
        f2=function () {    
            console.log("函数表达式--假区间");    
        }; 
    } 
    f2();//所有浏览器都返回 "函数表达式--真区间"
    

    函数中 this 指向

    应用环境this指向
    普通函数window对象方法当前实例对象定时器方法window构造函数实例对象原型对象方法实例对象
    //普通函数中
    this function f1() {    
        console.log(this); 
    } f1(); 
    
    //定时器中的this 
    setInterval(function () {    
        console.log(this); 
    },1000);
    
    //构造函数中this 
    function Person() {    
        console.log(this);    
        //对象方法中this    
        this.sayHi=function () {    
            console.log(this);    
        }; 
    } 
    
    //原型中的方法中this 
    Person.prototype.eat=function () {    
        console.log(this); 
    }; 
    var per=new Person(); 
    console.log(per); 
    per.sayHi(); 
    per.eat();
    
    //严格模式 "use strict";
    function f1() {  
        console.log(this);
        //window  
    } 
    f1();
    

    函数的不同调用方式

    //普通函数 
    function f1() {    
        console.log("普通函数"); 
    } 
    f1(); 
    
    //构造函数---通过new 来调用,创建对象 
    function F1() {  
        console.log("我是构造函数"); 
    } 
    var f=new F1();
    
    //对象的方法 
    function Person() {  
        this.play=function () {    
            console.log("玩玩玩");  
        }; 
    } 
    var per=new Person(); 
    per.play();
    

    函数是对象,对象不一定是函数

    对象中有 proto 原型,函数中有prototype原型,如果一个结构里既有prototype,又有 proto , 说明是函数,也是对象

    //对象中有__proto__原型,是对象 //函数中有prototype原型,是对象 
    function F1() { } 
    
    //函数中有prototype,也有__proto__ 
    console.dir(F1);
    
    //Math是对象  但不是函数没有prototype 
    console.dir(Math);
    
    //所有的函数实际上都是Function的构造函数创建出来的实例对象 
    var f1=new Function("num1","num2","return num1+num2"); 
    console.log(f1(1,2)); 
    console.log(f1.__proto__==Function.prototype);
    console.dir(f1); 
    console.dir(Function);
    

    apply和call方法的使用

    apply的使用语法

    函数名字.apply(调用该函数的对象,[参数1,参数2,...]);
    方法名字.apply(对象,[参数1,参数2,...]);

    call的使用语法

    函数名字.call(对象,参数1,参数2,...);
    方法名字.call(对象,参数1,参数2,...);

    作用:改变this的指向

    不同的地方:参数传递的方式是不一样的,apply参数是数组 ,call是参数列,逗号分隔

    只要是想使用别的对象的方法,并且希望这个方法是当前对象的,那么就可以使用apply或者是call的方法改变this的指向

    注意:

    apply和call方法中如果没有传入参数,或者是传入的是null,那么调用该方法的函数对象中的this就是 默认的window

    //调用函数 
    function f1(x,y) {    
        console.log("结果是:"+(x+y)+this);    
        return "test"; 
    }
    f1(10,20);
    //函数的调用
    f1.apply(); 
    f1.call();
    f1.apply(null); 
    f1.call(null); 
    //apply和call方法中如果没有传入参数,或者是传入的是null,那么调用该方法的函数对象中的this就是 默认的window 
    f1.apply(null,[100,200]); 
    f1.call(null,100,200); 
    var result1=f1.apply(null,[10,20]); 
    var result2=f1.call(null,10,20); 
    console.log(result1);
    console.log(result2);
    

    bind() 复制

    使用的语法:

    函数名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个函数 方法名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个方法

    复制了一份的时候,把参数传入到了f1函数中,x== >10,y==>20,null就是this,默认就是window bind方法是复制的意思,参数可以在复制的时候传进去,也可以在复制之后调用的时候传入进去 apply和call是调用的时候改变this指向 bind方法,是复制的时候,改变了this的指向

    function f1(x, y) {    
    	console.log((x + y) + ":=====>" + this.age); 
    } 
    function Person() {    
        this.age = 1000; 
    } 
    Person.prototype.eat = function () { 
        console.log("这个是吃"); 
    }; 
    var per = new Person(); 
    var ff = f1.bind(per, 10, 20); 
    ff();
    

    函数中的几个成员

    name:函数的名字,name 属性是只读的,不能修改

    arguments:实参 arguments[i] 实参的值 arguments.length 实参的个数

    length:形参的个数

    caller:函数的调用者

    闭包

    闭包的概念:函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者是数据,此时形成了闭包(这 句话暂时不严谨)

    闭包的模式:函数模式的闭包,对象模式的闭包

    闭包的作用:缓存数据,延长作用域链

    **闭包的优点和缺点:**缓存数据

    //函数模式的闭包:在一个函数中有一个函数
    function f1() {    
        var num=10;    
        //函数的声明    
        function f2() {     
            console.log(num);    
        }    
        //函数调用    
        f2(); 
    } 
    f1();//10
    
    //对象模式的闭包:函数中有一个对象 
    function f3() {    
        var num=10;    
        var obj={    
            age:num   
        };    
        console.log(obj.age);//10 
    } 
    f3();
    
     //普通的函数    
    function f1() {      
        var num = 10;      
        num++;      
        return num;    
    }    
    console.log(f1());    
    console.log(f1());   
    console.log(f1());         
    //函数模式的闭包    
    function f2() {      
        var num = 10;      
        return function () {        
            num++;        
            return num;     
     	}
    }    
    var ff = f2();    
    console.log(ff());    //11
    console.log(ff());    //12
    console.log(ff());	  //13
    

    总结:

    如果想要缓存数据,就把这个数据放在外层的函数和里层的函数的中间位置 闭包的作用:缓存数据.优点也是缺陷,没有及时的释放 局部变量是在函数中,函数使用结束后,局部变量就会被自动的释放 闭包后,里面的局部变量的使用作用域链就会被延长

    沙箱

    环境,在一个虚拟的环境中模拟真实世界,做实验,实验结果和真实世界的结果是一样,但是不会影响真实世 界。

    var num=10;   
    console.log(num+10);
    //沙箱---小环境   
    (function () {     
        var num=10;     
        console.log(num);   
    })();
    
    //沙箱---小环境   
    (function () {     
        var num=20;     
        console.log(num+10);   
    }());
    var num=100;   
    (function () {     
        var num=10;     
        console.log(num);//10   
    }());
       console.log(num);//100
    

    递归

    函数中调用函数自己,此时就是递归,递归一定要有结束的条件。

    //递归实现:求n个数字的和   n=5--->  5+4+3+2+1 
    //函数的声明 
    function getSum(x) {    
        if(x==1){     
            return 1;    
        }    
        return x+getSum(x-1); 
    } 
    //函数的调用 
    console.log(getSum(5));
    
    //递归案例:求斐波那契数列
    function getFib(x) {      
        if(x==1||x==2){        
            return 1      
        }      
        return getFib(x-1)+getFib(x-2);    
    }    
    console.log(getFib(12));
    

    浅拷贝

    拷贝就是复制,就相当于把一个对象中的所有的内容,复制一份给另一个对象,直接复制,或者说,就是把一个 对象的地址给了另一个对象,他们指向相同,两个对象之间有共同的属性或者方法,都可以使用

    var obj1={      
         age:10,      
         sex:"男",      
         car:["benchi","hafu","baoma","aodi"]   
    };    
    //另一个对象    
    var obj2={};        
    //写一个函数,作用:把一个对象的属性复制到另一个对象中,浅拷贝    
    //把a对象中的所有的属性复制到对象b中    
    function extend(a,b) {      
        for(var key in a){        
            b[key]=a[key];      
        }    
    }    
    extend(obj1,obj2);    
    console.dir(obj2);    
    console.dir(obj1);
    

    深拷贝

    拷贝还是复制,深:把一个对象中所有的属性或者方法,一个一个的找到.并且在另一个对象中开辟相应的空 间,一个一个的存储到另一个对象中。两者内存地址不同。

    var obj1={      
        age:10,      
        sex:"男",      
        car:["benchi","hafu","baoma","aodi"],      
        dog:{        
            name:"大黄",        
            age:5,        
            color:"黑白色"      
        }    };
    var obj2={};//空对象    
    //通过函数实现,把对象a中的所有的数据深拷贝到对象b中    
    function extend(a,b) {      
        for(var key in a){        //先获取a对象中每个属性的值        var item=a[key];        //判断这个属性的值是不是数组        
    if(item instanceof Array){          
        //如果是数组,那么在b对象中添加一个新的属性,并且这个属性值也是数组          
        b[key]=[];          
        //调用这个方法,把a对象中这个数组的属性值一个一个的复制到b对象的这个数组属性中          		     extend(item,b[key]);        
    }else if(item instanceof Object){
        //判断这个值是不是对象类型的          
        //如果是对象类型的,那么在b对象中添加一个属性,是一个空对象         
        b[key]={};
           //再次调用这个函数,把a对象中的属性对象的值一个一个的复制到b对象的这个属性对象中	          extend(item,b[key]);        
    }else{          //如果值是普通的数据,直接复制到b对象的这个属性中          
        b[key]=item;        
    		}      
        }    
    }
    extend(obj1,obj2);    
    console.dir(obj1);    
    console.dir(obj2);
    

    浅拷贝与深拷贝的区别:

    1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用

    2.深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”

    正则表达式

    元字符

    .  表示的是:除了\n(换行)以外的任意的一个字符   "fdsfs238" 
    [] 表示的是:范围,  [0-9] 表示的是0到9之间的任意的一个数字,  "789" [0-9] 
    [1-7] 表示的是1到7之间的任意的一个数字 
    [a-z] 表示的是:所有的小写的字母中的任意的一个 
    [A-Z] 表示的是:所有的大写的字母中的任意的一个 
    [a-zA-Z] 表示的是:所有的字母的任意的一个 
    [0-9a-zA-Z] 表示的是: 所有的数字或者是字母中的一个 
    [] 另一个函数: 把正则表达式中元字符的意义干掉   
    [.] 就是一个. 
    | 或者    
    [0-9]|[a-z] 表示的是要么是一个数字,要么是一个小写的字母 
    () 分组 提升优先级   [0-9]|([a-z])|[A-Z] 
    ([0-9])([1-5])([a-z]) 三组, 从左边开始计算
    
    都是元字符,但是也可以叫限定符,下面的这些
    * 表示的是:前面的表达式出现了0次到多次 
    [a-z][0-9]* 小写字母中的任意一个 后面是要么是没有数字的,要么是多个数字的 "fdsfs3223323"  
    
    + 表示的是:前面的表达式出现了1次到多次 [a-z][9]+  小写字母一个后面少一个9,或者多个9   "fesfewww9fefds"
    
    ?  表示的是:前面的表达式出现了0次到1次,少是0次,多1次 ,另一个含义:阻止贪婪模式 [4][a-z]? "1231234ij"  
    
    限定符:限定前面的表达式出现的次数
    {} 更加的明确前面的表达式出现的次数 
    {0,} 表示的是前面的表达式出现了0次到多次,和 *一样的 
    {1,} 表示的是前面的表达式出现了1次到多次,和 +一样的 
    {0,1} 表示的是前面的表达式出现了0次到1次,和 ?一样的 
    {5,10} 表示的是前面的表达式出现了5次到10次 {4} 前面的表达式出现了4次
    
    方括号用于查找某个范围内的字符:
     ^ 表示的是以什么开始,或者是取非(取反) ^[0-9] 以数字开头
     ^[a-z] 以小写字母开始 
     [^0-9] 取反,非数字 
     [^a-z] 非小写字母 
     [^0-9a-zA-Z_]
     
    $ 表示的是以什么结束  
    [0-9][a-z]$  必须以小写字母结束 
    ^[0-9][a-z]$ 相当于是严格模式   "3f2432e"  "4f"  
    
    修正符\元字符
    \d 数字中的任意一个, 
    \D 非数字中的一个
    \s 空白符中的一个
    \S 非空白符
    \w 非特殊符号 
    \W 特殊符号
    \b 匹配单词边界
    \uxxxx  查找以十六进制xxxx规定的Unicode字符
    
    修饰符
    g 全局匹配
    i 不区分大小写
    m 多行匹配
    x 忽略正则表达式中的空白
    U 拒绝贪婪
    
    .*   贪婪模式
    .*?  非贪婪模式
    
    反向引用
    当我们匹配一个字符串的时候,可能会需要获取原字符串中的内容,此时我们可以这样做
    //源字符串
    2017-10-14
    //正则
    (\d{4})-(\d{2})-(\d{2})
    //需要转换成 10/14/2017的格式,就用到反向表达式
    $2/$3/$1
    在正则中被分组的字符,我们可以通过$1 $2 $3...来捕获,如果需要引用原字符串的内容,只需要引用对应的 $1 $2 $3...即可。
    

    创建正则表达式对象

    //1.通过构造函数创建对象 
    var reg=new RegExp(/\d{5}/); 
    //字符串
    var str="我的电话是10086"; 
    //调用方法验证字符串是否匹配 
    var flag=reg.test(str); console.log(flag);
    //对象创建完毕--
    var reg=new RegExp(/\d{5}/);
    //调用方法验证字符串是否匹配 
    var flag=reg.test("我的电话是10086");
    console.log(flag);
    
    //2.字面量的方式创建正则表达式对象
    var reg=/\d{1,5}/;
    var flag=reg.test("小苏的幸运数字:888"); 
    console.log(flag);
    

    身份证号 /^\d{17}(\d|[a-z])$/

    手机号 /^\d{11}$/

    qq号 /^\d{5,11}$/

    固话 /^\d{3,4}[-]\d{7,8}$/

    邮箱 /^\w+@\w+( \ .\w+){1,3}$/

    日期 /\d{4}-\d{1,2}-\d{1,2}/

    表单验证思路:

    利用失去焦点事件onblur,(同时定义一个布尔值作为返回值,用作最后整体提交),判断如果值为空则提示输入值,如果有值则判断格式是否正确,格式错误返回false,格式正确返回true,最后在提交表单时整体验证只有所有都为true才可以提交。

    正则表达式中的方法

    search()

    search() 用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的字符串,并返回起始位置。

    参数:正则或要查询的字符。

    返回值:查询字符的起始位置。

    使用正则搜索字符串,不区分大小写:

    var str = "hello world";
    var n = search(/ld/i);
    console.log(n);
    

    使用字符搜索字符串,不区分大小写:

    var str = "hello world";
    var n = search("ld");
    console.log(n);
    

    repalce()

    repalce()用指定字符替换其他字符,或替换与正则匹配的字符。

    参数:要修改的字符/匹配的正则,要替换的字符。

    返回值:修改后的字符串。

    var ss = "this is a good day";
    var nn = ss.replace("good","bad");
    //var nn = ss.replace(/good/i,"bad");
    console.log(nn);//this is a bad day
    

    test()

    test()检测字符串是不是匹配某个模式,如果有匹配文本则返回true,否则返回false。

    redExp.test();

    var res = /e/.test("the best thing in the life are free");
    console.log(res);//true
    

    exec()

    检索字符串中正则的匹配。

    redExp.exec();

    /e/.exec("this is the best thing , free");
    

    起源地下载网 » JavaScript 进阶技能,中高级前端必备|8月更文挑战

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元