【无标题】

匿名函数

//匿名函数:没有名字的函数
//常见的使用方式

   //1.
     document.onclick = function(){
     }
    //2.
     let f = function(){
     }
    //3.
     setInterval(function(){
     },1000);
// 由以上得出结论->函数也是一种对象
// 目的了解函数的作用
// 特殊函数使用方法
// a.回调函数->一个被当做参数的函数
// b.函数也可以当做函数的返回值->闭包的前置条件

自运行:

函数在定时时,同时被调用,只针对匿名函数
a、方法一
(funtion(){console.log(“今天星期一嘤嘤嘤”);})();
b、方法二
(funtion(){
console.log(“heihei”);
}());
c、关键字
void function(){
console.log(“1111”);
}();

! function(){
console.log(“222”);
}();

闭包的概念

1、闭包的概念:函数嵌套函数,被嵌套的函数称为闭包函数
2、闭包的作用:可以在函数体外使用局部变量
3、闭包的实现:在父函数f1中定义的局部变量count,和子函数f2
在f2中操作沙盒变量count,将子函数f2作为父函数f1的返回值,在外界通过全局变量f绑定f1的返回值,从而实现了闭包
4、闭包的缺陷:闭包会打破垃圾回收机制,可能会造成内存泄漏

//第一种
functio f1(){
	var count = 0;
	var f2 = function(){
		count++;
		return count;
	}
	return f2;
}
	let  f = f1();//f1()== f2 ==f
	console.log(f());
	console.log(f());
	console.log(f());

//第二种
	let f = (function(){
		var count = 0;
		return++count;
		}
	}()};
	console.log(f());
	console.log(f());

闭包的作用-沙盒

背景:类的设计中,属性和方法是有共有和私有的要求,通常来说,所有的属性都是私有,所有的方法都是共有,外界修改私有属性应该只能通过类提供的共有方法实现
沙盒的概念->类的公有和私有的概念->块级作用域
强调get和set方法,对私有属性的修改

垃圾回收机制

对象在创建后需要销毁空间,销毁变量空间的工作是由垃圾回收机制完成的,称为GC机制。
1、标记法:一个变量进入该作用域给一个标记,离开该作用域收回标记,然后销毁
2、引用计数法:在程序中任何一个位置使用到了该变量则计数器+1,停止使用该变量时计数器-1
优点:简单,概念清晰,效率高
缺点:遇到循环引用无法实现

函数的柯里化

只有一个参数,且返回值为一个函数的函数,称为柯里化函数
作用:
柯里化实际是把简单的问题复杂化了,但是复杂化的同时,我们在使用函数时拥有了更加多的自由度。
而这里对于函数参数的自由处理,正是柯里化的核心所在。 柯里化本质上是降低通用性,提高适用性。

function fun(regExp){
        return function(str){
            return regExp.test(str);
        }
    }

    //验证用户名
    let regUserName = fun(/\D\w{5,17}/);
    console.log(regUserName("laowang"));
    console.log(regUserName("123"));

    //验证密码
    let regUserPwd = fun(/.{6,}/);
    console.log(regUserPwd("heihei"));
    console.log(regUserPwd("12"));

函数对象

// JS中万物皆为对象,函数当然也是一个对象
// 函数对象是什么类型的?->引用类型->new

//函数定义的方式
//a.
// function f1(){
// }

//b.
// let f2 = function(){
// }

//c.构造方法创建函数
// let 函数名 = new Function(["参数列表"],"代码块");  
// let f3 = new Function("console.log('abc')");
// f3();
// let f4 = new Function("a","b","console.log(a+b)");
// f4(1,3);

arguments:函数的内置对象,作用域只能出现在函数体内(用来保存函数形参的数组)
用来保存函数形参的数组,它是一个伪数组,只能进行数组元素的读,和使用length属性,其他的API不能使用

a、定义不定参函数
	 function fun() {
        // console.log(arguments);
        for(let i=0; i<arguments.length; i++){
            console.log(arguments[i]);
        }
    }

    fun(1,"嘿嘿嘿",2);

  案例:
    function fun(){
        for(let i=0; i<arguments.length; i++){
            if(typeof arguments[i] == "number"){
                console.log("执行数字操作");
            }else if(typeof arguments[i] == "string"){
                console.log("执行字符串操作");
            }else if(typeof arguments[i] == "boolean"){
                console.log("执行布尔操作");
            }
        }
    }
    fun(true,2);
    
b、递归中如果函数名改名,可以不用改函数内部的名字(arguments.callee:代表函数对象本身)
  arguments.callee:代表函数对象本身
    function fun(){ // fun == arguments.callee
        // console.log(fun);
        console.log(arguments.callee);
    }

    fun();

this

this:函数体内的内置对象->作用域必须在函数体内

//1.与事件体连用,代表触发该事件的元素
    document.onclick = function(){
        console.log(this);
    }

//2.与构造函数连用,代表new出来的对象
    function Student(name){
        this.name = name;
        console.log(this);
    }
    let s = new Student("蔡徐坤");

//3.与普通函数(除了构造函数和事件体)连用,代表调用该函数的对象
    function fun(){
        console.log(this);
    }
    fun();
    let data = {
        "a":1,
        "fun":function(){
            console.log(this);
        }
    }
    data.fun();
 
//4.与箭头函数连用,代表其父元素的前缀
    document.onclick = ()=>{
        console.log(this);
    }
    let data = {
        "a":1,
        "fun":()=>{
            console.log(this);
        }
    }
    data.fun();

prototype

前言:类对象在创建时,属性属于每一个对象,所以要开辟独立的空间,而行为或者方法属于整个类族,所有该类的对象都共享该方法,不应该为每一个对象都开辟共享方法的空间
prototype:原型对象,每一个函数(主要强调的是构造函数)都有一个prototype属性,prototype对象存储这该类所有实例对象共享的属性和方法
实例对象不能修改原型属性的值,如果一个实例对象这么做,等于为该实例对象添加了一同名个自定义属性
为什么实例对象可以访问所有的属性和方法?->原型图
实例对象的自定义属性是直接在堆上开辟空间的,所以可以直接访问,每一个实例对象都有一个__proto__属性,该属性指向类的原型对象,console.log(Student.prototype == s1.proto);所以实例对象可以访问原型对象上的属性和方法

apply和call

apply和call是函数对象的成员函数,可以改变函数的this指向,
函数对象.apply(被修改的this指向,[参数1,参数2…]);
函数对象.call(被修改的this指向,参数1,参数2…);

let d = new Dog("旺财");
eat.apply(d,["狗粮","火腿"]);
eat.call(d,"蛋糕","骨头");
let c = new Cat("Tom");
eat.apply(c,["Jerry","鱼"]);
eat.call(c,"猫粮","猫条");
------------------------------------------------
apply,call,bind的异同?
1.都是用来改变this指向的
2.bind通常用来修改匿名函数
document.onclick = function(){
    this.xxxx
}.bind(xxx);
3.apply和call通常改变有名函数
4.apply的第二个参数是数组,call不是,bind的参数和call一毛一样
5.apply和call会直接调用该函数,而bind只是产生了一个新的函数对象

继承

继承:子类继承父类派生的属性和方法,可以直接使用。子类还可以添加自己新的属性和方法。
作用:提高了代码的复用性
继承的类型:
一、原型继承
原型继承:通过原型对象prototype实现继承,
如何实现继承,用子类的原型对象指向父类的实例对象
语法为: 子类.prototype = new 父类();
原型继承的缺陷:
1.必须先实现继承关系,才能添加原型对象上的方法或属性
2.一旦实现原型继承关系,子类原型对象的值就不能改变
3.原型继承无法初始化由父类派生给子类的属性

凭什么子类对象可以访问所有的属性和方法?->原型链
子类实例对象可以直接访问new出来堆空间的属性,
子类实例对象通过__protp__指向子类的原型对象,所以可以访问子类原型对向上的方法或属性,
子类的原型对象指向其父类的实例化对象,所以可以访问父类的属性,
父类实例化对象的__proto__指向其父类的原型对象,所以可以访问父类原型对象上的方法或属性
向上找->先在自身找,找不到往上找

二、apply和call继承
apply和call继承,也称为借用构造函数"继承"
好处:可以实现由父类派生给子类的属性,在构造时可以初始化
缺点:无法继承原型对象上的属性或方法

三、混合继承
//混合继承:
//用原型继承,继承原型对象上的方法或属性
//用借用构造方法继承,继承父类派生给子类的属性

  function Human(name,id){
        this.name = name;
        this.id = id;
    }
    Human.prototype.eat = function(){
        console.log("Animal eat");
    }
    function Student(name,id,score){
        //实现属性继承
        Human.call(this,name,id);
        this.score = score;
    }

    //实现原型对象继承
    Student.prototype = new Human();
    Student.prototype.study = function(){
        console.log("study");
    }
    let s = new Student("老王",1,100);
    console.log(s.name,s.id,s.score);
    s.eat();
    s.study();

四、ES6继承

<script>
    class Human{
        constructor(name,id){
            this.name = name;
            this.id = id;
        }
        eat(){
            console.log("eat");
        }
    }
    // 通过extends关键字实现继承
    // class 子类 extends 父类{
    // }
    class Student extends Human{
        constructor(name,id,score){
//super是代替父类构造函数的关键字,等价于调用父类构造函数
//super必须写在构造函数的第一行
            super(name,id);
            this.score = score;
        }
        study(){
            console.log("study");
        }
    }
</script>

设计模式

类的一种设计方案
目的:根据不同的场景,大家统一思想,用相同的设计方案去解决该问题。从而实现程序的可持续性,维护性。
定义:模式是在一个上下文中,对一个问题的解决方案。即模式的四要素:名字、上下文、问题、和解决方案

为什么使用设计模式:
1、尽量用一种标准的方式描述设计经验
2、为设计者提供一种通用的语言
3、增加复用性,减少设计的多样性
4、增强设计变更的灵活性
5、提高设计文档的质量
6、增强设计的可理解性

策略模式

策略模式是行为模式的一种,在例如java语言的表现是通过处理对象和行为的关系,通过多态性来消除if-else分支,而每一个分支都算是一个策略,以此来达到统一的变化。而在js中,多态性是自然而然就存在了,下面将以js的方式演示如何使用策略模式。策略模式为用户提供了自己编写if。。。else的机会

class Calc{
        constructor(){
            //保存策略的地方(if或else的各种条件)
            this.data = {
                // "add":function(a,b){
                //     return a + b;
                // }
            }
        }
        //添加策略内容
        //name是添加函数的名字
        //opt其实就是分支
        addFun(name,fun){
            this.data[name] = fun;
        }
        //添加好功能的调用
        fun(name,a,b){
            //              add(1,2)
            return this.data[name](a,b);
        }
    }
    let c = new Calc();
    c.addFun("add",function(a,b){
        return a + b;
    });
    c.addFun("min",(a,b)=>a-b);
    let x = c.fun("add",1,2);//add(1,2)
    console.log(x);
    x = c.fun("min",2,5);
    console.log(x);

观察者模式

观察者模式:也称为订阅发布者模式,该模式由两个类构成,一方是发布者(主题),另一方是观察者,也称为(订阅者).实现的功能最常见就是订阅公众号,凡是订阅了该主题的观察者,在观察者发出消息后,都会接收的该消息。
实现:
订阅者写函数定义
发布者写函数调用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值