• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

JavaScript笔记&2

开发技术 开发技术 4小时前 2次浏览

一、面向对象编程

1.面向对象编程介绍

1.1两大编程思想

  1. 面向过程 POP

    • 面向过程就是分析解决问题所需要的步骤,然后用函数一步一步实现,在依次调用
  2. 面向编程 OOP

    • 面向对象是把事务分解成一个个对象,然后去由对象之间工作与合作
    • 在面向对象程序开发思想中,每个对象都是功能中心,具有明确分工
    • 面向对象具有灵活、代码可复用性、容易为维护等优点
  3. 面向对象三个特性,继承、封装、和多态

    • 封装
    • 继承
    • 多态

1.2 各自的优缺点

  • 面向过程
    • 优点:性能高,与硬件联系紧密,例如单片机采用面向过程编程
    • 缺点:不易维护,不易服用,不易扩展
  • 面向对象
    • 优点:易维护,易复用,扩展,由于疯转继承和多态的特性,容易开发出低耦合的系统,更加灵活
    • 缺点:性能没有面向过程高

2.ES6中的类和对象

  • 面向对象思维特点:
    1. 抽象对象公共的功能,封装成一个类/函数(模板)
    2. 实例化对象
    3. 万物皆对象
  • JavaScript中万物皆兑现
    • 属性:事物的特征,用对象中的属性表示
    • 方法:事物的行为动作,用对象中的方法来表示

2.1 创建类

  1. 通过关键字class创建类,类名习惯性首字母大写
  2. 类里面有constructor构造函数,又来接受参数,同时返回对象实例
  3. constructor构造函数,当我们使用new实例化对象的时候,系统会自动调用构造函数,如果我们不写构造函数,那么系统会默认生成一个构造函数
  4. 必须使用new实例化对象
  5. 创建类的格式和语法规范,class 类名{constructor(){} }
<	script>
    class Star{
    	constructor(name){
            this.name = name;
        };
	};
    
    
	var ldh = new Star('刘德华');
    console.log(ldh.name) // 刘德华
    var ldh = new Star('张学友');
    console.log(ldh.name) // 张学友
</script>

2.2 类中的方法

2.2.1 创建方法
  • 类中创建方法直接方法名小括号大括号就行了,不需要使用function关键字
<script>
	class Star{
        constructor(name,age){
            this.name = name
            this.age = age
        }
        sing(){
            console.log('我是普通的方法')
        }
    }
    var ldh = new Star('刘德华',18);
    ldh.sing();
    var ldh = new Star('张学友',19);
    ldh.sing();
</script>
  • 在类中的方法之间不需要添加逗号分隔
2.2.2 方法的参数
<script>
	class Star{
        constructor(name,age){
            this.name = name
            this.age = age
        }
        sing(song){
            console.log('我是'+this.name)
            console.log('我唱的歌是'+song)
        }
    }
    var ldh = new Star('刘德华',18);
    ldh.sing('冰雨');
    var ldh = new Star('张学友',19);
    ldh.sing('吻别');
</script>

2.3 类的继承

  • 子类继承父类的属性和方法

  • JavaScript中的继承使用关键字extends

    <script>
    	class Father{
            constructor(){
                
            }
            money(){
                console.log(10000000)
            }
        }
        class Son extends Father{
            
        }
        var son = new Son();
        son.money();
    </script>
    
2.3.1 super关键字
  • super关键字用于访问和调用对象父类的函数,可以调用父类的构造函数,也可以调用父类的普通函数

  • super可以调用父类的属性

    <script>
    	class Father{
            constructor(x,y){
                this.x = x;
                this.y = y;
            }
            sum(){
                console.log(this.x + this.y);
            }
        }
        class Son extends Father{
            constructor(x,y){
                super(x,y);
            }
        }
        var son = new Son(2,3);
        son.sum();
    </script>
    
  • 也可以调用父类的方法

    <script>
    	class Father{
            say(){
                return '我是爹
            }
        }
        class Son extends Father{
            say(){
                console.log('我是儿')
               	如果子类中有方法,先调用子类的
                super.say() 可以调用父类中的方法
            }
        }
        var son = new Son();
        son.say();
    </script>
    
  • 子类继承父类的方法并且扩展自己的方法

    <script>
    	class Father{
            constructor(x,y){
                this.x = x;
                this.y = y;
            }
            sum(){
                console.log(this.x + this.y);
            }
        }
        class Son extends Father{
            constructor(x,y){
                super(x,y); // 必须先调用super
                this.x=x;
                this.y=y;
            }
            sub(){
                console.log(this.x-this.y)
            }
        }
        var son = new Son(2,3);
        son.sum();
        son.sub();
    </script>
    

    注意,super放在前面,这样才能及使用自己的方法,也是用父类的方法

  • 三个注意点

    • es6中没有变量提升,类要在实例化前面
    • 类中共有的属性和方法要使用this调用
    • 类中this指向问题

2.4 构造函数和原型

  • 在ES6之前是没有class的,没有引入类的概念

  • 在Es6之前,对象不是基于类创建的,而是一种称为构造函数的特殊函数来定义对象和它们的特征

  • 创建语法

    function Star(name,age,sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.sing = function(song){
            console.log(song)
        }
    }
    var ldh = new Star('刘德华',12,'男');
    console.log(ldh.name)
    ldh.sing('冰雨')
    
    1. 构造函数是一个特殊的函数,主要用来初始化对象,对象成员变量赋值,配合new一起使用,可以将一些对象的公共部分封装在构造函数中
    2. new执行步骤
      1. 在内存中创建新对象
      2. 让this指向这个对象
      3. 执行构造函数里面的代码,给对象添加属性和方法
      4. 返回这个新对象,所以不需要return
2.4.1 构造函数的成员
  • JavaScript构造函数中,可以在构造函数本身添加成员,也可以在this内部添加成员,通过两种方式添加的成员分别是静态成员实例成员

    • 静态成员:在构造函数本身添加的成员,只能由构造函数本身去访问

    • 实例成员:在构造函数内部创建的对象成员,只能由实例化对象来访问

      function Star(name,age){
          this.name = name;
          this.age = age;
          this.sing = function(song){
              console.log(song)
          }
      }
      
      var star = new Star()
      star.name;// 静态成员只能通过实例化来访问【name,age,sing】
      Star.sex = '男'; // 使用构造函数本身添加属性,只能通过本身去访问
      console.log(Star.sex)
      
2.4.2 原型
  • 构造函数内部使用复杂数据类型会另外开辟空间,比较消耗资源,每次实例化一个对象,都会开辟空间

    function Star(name,age){
        this.name = name;
        this.age = age;
        this.sing = function(song){ // 每次实例化一个对象,内存都会再开辟一款空间单独存储这个函数
            console.log(song)
        }
    }
    
  • 构造函数原型可以实现构造函数中的函数,所有的对象都可以共享

  • prototype,JavaScript规定每一个函数都有一个prototype属性,指向另一个对象(prototype就是一个对象),这个对象所有属性和方法都会被构造函数所拥有

  • 我们可以把那些不变的方法,直接定义到prototype(原型)对象上,这样所有的对象实例就可以共享这些方法了

    function Star(name,age){
        this.name = name;
        this.age = age;
    }
    Star.protopyte.sing = function(){  // Star.protopyte就是原型对象
            console.log('我爱唱歌')
        }
    var ldh = Star('刘德华',19)
    var zxy = Star('张学友',19)
    console.log(ldh.sing()) // 我爱唱歌
    console.log(ldh.sing()) // 我爱唱歌
    
  • 对象都会有一个__proto__属性,其属性指向构造函数的原型prototype对象,所以对象实例化可以调用构造函数prototype对象

2.4.3 constructor
  • 对象原型__proto__和构造函数原型prototype,都有一个属性constructor,我们称之为构造函数,他指向构造函数本身
  • constructor主要作用就是记录该对象引用哪个构造函数,它可以让原型对象重新指向原来的构造函数
function Star(name,age){
    this.name = name;
    this.age = age;
}
Star.prototype = { // 很多情况我们需要手动利用constructor来指向原来的构造函数
    constructor: Star; // 我们修改了原来的原型对象,给原型对象(prototype)赋了一个新的对象,我们必须使用constructor指回原来的构造函数
    sing: function(){
        
    };
    dance: function(){
        
    }
}

var ldh = new Star('刘德华',18)
var zxy= new Star('张学友',18)
console.log(ldh.__proto__)
console.log(zxy.__proto__)
console.log(Star.prototype.constructor)

构造函数,实例,原型对象之间的关系

构造函数指向构造函数的原型对象prototype,原型对象的属性constructor又指向了构造函数

构造函数new一个对象,这个对象中有一个属性__prot__,这个属性又指向了prototype(对象原型)

实例.__proto__.constructor

  • 原型链

    构造函数中的prototype原型对象也是一个对象,也有__proto__,而它指向的是Object.prototype

    JavaScript笔记&amp;2

  • JavaScript中的成员查找机制就是按照原型链来查找

  • 圆形对象this指向问题

    • 在构造函数中,this指向的就是对象实例

    • 原型对象中的this指向的也是对象实例

      function Star(name,age){
          this.name = name;
          this.age = age;
      }
      var that;
      Star.protopyte.sing = function(){  // Star.protopyte就是原型对象
              console.log('我爱唱歌');
          	that = this;
          }
      var ldh = Star('刘德华',19)
      var zxy = Star('张学友',19)
      console.log(ldh.sing()) // 我爱唱歌
      console.log(ldh.sing()) // 我爱唱歌
      
2.4.4 构造函数继承
  • es6之前没有提供extends继承,而是通过构造函数+原型对象模拟继承的,也叫做组合继承

  • call()

    • 调用这个函数,并修改函数运行时的this指向
    • thisArg:当前调用函数的this指向对象
    • arg1,arg2,穿的的参数
    function func(a,b){
        console.log('我要吃米饭');
        console.log(a+b)
    }
    func.call(); // call也可调用函数
    
    var s ={
        name:'张三',
    }
    func.call(s); // 此时func中的this指向的就是s这个对象
    func.call(s,1,2); // call中的第一个参数就是改变this指向的,后面的参数就是世纪传入的参数
    
  • call继承父类的属性

    function Father(anme,age){
        this.name = name;
        this.age = age;
    }
    function Son(anme,age){
        Father.call(Son,name,age);// 改变了this指向,就可以使用父类的属性了
    }
    
  • call继承父类的方法

    function Father(anme,age){
        this.name = name;
        this.age = age;
    }
    
    Father.prototype.zhengqian = function(){
        console.log('挣钱')
    }
    
    function Son(anme,age){
        Father.call(Son,name,age);// 改变了this指向,就可以使用父类的属性了
    }
    Son.prototype = Father.prottype; // 改变了this指向,就可以使用父类的属性了
    // 子类有自己的方法,上面这种赋值直接将子类的原型对象的引用指向了父类的原型对象,如果修改了子原型对象,父类原型对象也会改变
    // 核心
    Son.prototype = new Father();
    

2.5 ES5方法

2.5.1 数组
  • forEach(),迭代

    // array.forEach(function(currentValue,index,arr))
    // function:回调函数
    // currentValue:数组当前项的值
    // index:当前项索引
    // arr:数组对象本身
    var arr = [1,2,3]
    arr.forEach(function(value,index,arr){
        console.log(
        	'当前值'+value,
            '当前下标'+index,
            '当前数组'+arr,
        )
    })
    
  • filter(),过滤

    /*
    array.filter(function(currentValue,index,arr))
    filter用来创建一个新的数组,主要是筛选满足条件的元素,返回新数组
    function:回调函数
    currentValue:数组当前项的值
    index:当前项索引
    arr:数组对象本身
    */
    var arr = [1,2,3,4,5,6,7]
    var newArr = arr.filter(function(value,index,arr){
        return value>=4;// 大于四的
    })
    console.log(newArr);// [4,5,6,7]
    
  • some(),查找元素

    /*
    array.some(function(currentValue,index,arr))
    some 主要是筛选满足条件的元素,返回的是true或者false
    找到第一个满足条件的元素就终止循环返回true,如果没有即返回false
    function:回调函数
    currentValue:数组当前项的值
    index:当前项索引
    arr:数组对象本身
    */
    var arr = [1,2,3,4,5,6,7]
    var newArr = arr.some(function(value,index,arr){
        return value>=4;// 大于四的
    })
    console.log(newArr);// true
    
2.5.2 字符串
  • trim() 去除空白字符

    /*
    str.trim()
    去除首尾空白符
    不影响字符串本身,返回一个新的字符串
    */
    var str = '   helloworld  '
    var newStr = str.trim()
    onsole.log(newStr);// helloworld
    
2.5.3 对象方法
  • 对象的遍历Object.keys()

    var obj = {
        id : 1,
        name : '张三',
        age : 19
    }
    Object.keys(obj)
    
  • Object.defineProperty() 定义对象中新属性,或者修改属性

    /*
    Object.defineProperty(obj,prop,descriptor) 必须传入三个属性
    obj:目标对象
    prop:需要修改属性的名字
    descriptor:目标属性所拥有的特征,这个参数以对象的形式书写
    		value:设置属性值默认undefined
    		writable:值是否可以重写,true false,默认false
    		enumerable:目标是否可以被枚举 true false,默认false
    		configurable:目标书型是否可以被删除,或者被修改 true false,默认false
    */
    var obj = {
        name : 'z',
        id : 1,
        age : 10
    }
    Object.defineProperty(obj,name,{
        value:'lisi',
        
    })
    

3.函数进阶

3.1函数的定义和调用

  1. function关键字声明函数(明明函数)

    function fn(){
        
    }
    
  2. 函数表达式(匿名函数)

    var fn = function(){
        
    }
    
  3. new Function() (构造函数)

    var fn = new Function('参数1','参数2','函数体') // 参数必须加引号
    var fn = new Function(console.log(123))
    
  4. 所有函数都是Function的实例,函数也属于对象

    var fn = new Function(console.log(123))
    console.log(fn)
    console.log(fn instanceof Function)
    
  • 函数的调用

    普通函数
    function fn(){
        
    }
    fn();
    对象函数
    var o = {
        func : function(){
        }
    }
    o.func();
    构造函数
    function Star(){
        
    }
    new Star();
    绑定事件函数
    btn.onclick = function(){
        
    } 点击按钮调用
    
    定时器函数
    setInterval(function(){},1000); 定时器自动调用 1秒/次
    
    立即执行函数
    
    (function(){
        
    })();不需要调用,自动执行
    

3.2 this

  • this指向是当我们调用函数时候才确定的,调用的方式不同,指向不同

    调用方式 this指向
    普通函数调用 window
    构造函数调用 实例对象,包括原型对象里面的this也是指向实例对象
    对象方法调用 该方法所属对象
    事件方法调用 绑定事件对象
    定时器函数 window
    立即执行函数 window
  • 改变this指向

    • call()

      var o = {
      	name:'zhangsan'    
      }
      function func(){
          
      }
      func.call()
      func.call(o)
      
      function Father(name,age){
          this.name = name;
          this.age = age
      }
      function Son(name,age){
          Father.call(this,name,age)
      }
      var son = new Son('张三',15)
      console.log(son)
      
    • bind()

      // 用来的调用一个函数,但是也可以改变this的指向
      func.bind(thisArg,args1,args2...])
      thisArg:指定this的值
      argsArray:参数数组
      返回指定this的值和初始化参数改造的原函数
      
      var o = {
      	name:'zhangsan'    
      }
      function func(){
          
      }
      var newFun = func.bind();不会调用,只是绑定了方法而已
      newFun();调用
      

      有时候并不需要调用函数,但是又想改变这个函数内部this的指向

      常用

      var btn = document.querySelector('button');
      btn.onclick = function(){
          this.disabled = true;// 这个this指向的是btn这个按钮
          setTimeout(function(){
              this.disabled = false; // 此时函数里面的this指向的就是btn
          }.bind(this),3000); // 这个this 指向的是btn这个对象
      }
      
    • apply()

      // 用来的调用一个函数,但是也可以改变this的指向
      func.apply(thisArg,[argsArray])
      thisArg:指定this的值
      argsArray:参数数组
      返回值就是函数的返回值,因为它就是调用函数的
      
      求数组中的最大值
      var arr = [1,2,3,4,5,99]
      var max = Math.max.applay(Math,arr)
      console.log(max);99
      

3.3 高阶函数

  • 高阶函数是指对其他函数操作的函数,一个函数的参数或者返回值是另一个函数,这个函数就是高阶函数

  • 函数也是数据类型,只要是数据类型就可以作为参数或者返回值

  • 作为参数传递

    function fn(a,b,callback){
        console.log(a+b);
        callback && callback();// 代码执行完执行回调函数
    }
    fn(1,2,function(){
        console.log('我是作为参数的函数,我是最后打印的,因为我在最后面')
    })
    
    
  • 闭包函数Closure

    • 变量根据作用域的不同分为全局变量和局部变量

    • 在函数内部可以使用全局变量,但是在函数外部不可以使用函数中的变量

    • 闭包函数的定义,闭包就是一个函数,指有权利访问另一个函数中的局部变量

      function fn(){    var number = 10;    function func(){        console.log(number);    }    func();}// func就是闭包函数fn();
      
    • 闭包函数的作用

      // 再外部作用域访问内部的变量function fn(){    var number = 10;    function func(){        console.log(number);    }    return func;}var f = fn()f();// func()// func就是闭包函数fn();
      
    • 递归函数

      • 函数内部调用自己
      function fn(){
          fn();
      }
      
      function js(n){
              if(n===1){
                  return 1;
              }else{
                  return n*js(n-1);
              }
          }
      

3.4 浅拷贝和深拷贝

  • 浅拷贝:浅拷贝只拷贝一层,更深级别的只拷贝引用

    var obj = {
        name:'zs',
        age:19,
        msg:{
        sss:1
    }
    }
    
    var o ={};
    for (var k in obj){
        o[k] = obj[k]
    }
    o.msg.sss = 10
    console.log(o)
    console.log(obj.msg.sss) 10
    
  • 深拷贝(完全复制)【使用递归】

    var o = {
        name:'张三',
        age: 18,
        info: {
            sss: '你好',
        },
        arr: [1,2,3]
    }
    var s = {}
    // 封装函数
    function deepCopy(newObj,oldObj){
        // 遍历旧对象
        for(var k in oldObj){
            // 获取对象中的值
            var temp = oldObj[k]
            // 判断temp的类型,如果是对象类型
            if(temp instanceof Array){
               newObj[k] = [];
               deepCopy(newObj[k],temp)
               }else if(temp instanceof Object){
                    newObj[k] = {};
                    deepCopy(newObj[k],temp)
               }else{
                   newObj[k] = temp
               }
        }
        return newObj;
    }
    var a = deepCopy(s,o);
    console.log(a);
    

4.正则表达式

  • 主要就是用来匹配替换提取字符串的

4.1 使用正则表达式

  1. 通过RegExp对象的构造函数来创建

    var regexp = new RegExp(/表达式/);
    
  2. 字面量创建

    var re = /表达式/;
    
  3. 检测字符串是否符合正则表达式规范test

    var re = /123/;
    console.log(re.test(123)); // true
    console.log(re.test('123')); // true
    
  4. 正则表达式中的替换replace

    stringObject.replace(re/substr,replacement)
    返回一个替换完毕的新字符串
    var newStr = stringObject.replace(re/substr,replacement)
    console.log(newStr)
    

5. ES6新增

5.1 let

  • let是用来声明变量的

  • let 声明的变量只有在所处的块级生效

  • es6中新增了块级作用于的概念,就是再{}中就是块级作用域

if (true){
    let a = 'a';
    var s = 's'
}
console.log(a);
c
  • 在一个打括号中,使用let声明的变量才具有块级作用域的特点的,var不具有
  • 使用let声明变量不存在变量提升

5.2 const常量

  • 常量对应的内存地址不可更改,也就是值不可更改

    // 具有块级作用域的特点
    if (true){
     	const a = 'a'   
    }
    console.log(a); 未定义
    
    // 使用const声明变量是必须赋初始值
    
  • 常量值不可更改,但是对于引用数据类型来说可以更改里面元素的值

5.3 解构赋值

var [a,b,c] = [1,2,3]
console.log(a); 1
console.log(b); 2
console.log(c); 3 
// 变量多于元素,没有分配到的变量就是undefined
  • 对象结构

    let person = {
        name:'z',
        age:12
    }
    let {a,b} = person; // 注意是{}
    
    console.log(a) z
    console.log(b) 12
    ----------------
    let person = {
        name:'z',
        age:12
    }
    let {a:c,b:d} = person; // 注意是{}
    
    console.log(a) name
    console.log(b) age
    console.log(c) z
    console.log(d) 12
    

5.4 箭头函数

  • 用来简化语法

    () => {};
    var fn = () => {};
    函数体中如果只有一句代码,且代码的执行结果就是返回值,那么就可以省略大括号
    var sum = (a, b) => a + b
    

    箭头函数不绑定this关键字,箭头函数中的this指向的就是函数定义的上下文的this

    如果使用this,this就是箭头函数所在位置

5.5 剩余参数 …args

  • 不定量参数表示为一个数组
function fn(first,...args){
    console.log(first); // 1
    console.log(args); // [2,3]
}
fn(1,2,3)
  • 和机构赋值配合使用

    var arr = [1,2,3]
    var [a,...b] = arr;
    console.log(a)
    console.log(b)
    

5.6 扩展运算符

  • 将数组或者对象转换为用逗号分隔的参数序列,和剩余参数相反

    let arr = [1,2,3]
    // ...arr
    console.log(...arr)
    
  • 合并数组

    let arr1 = [1,2,3]
    let arr2 = [3,4,5]
    let arr3 = [...arr1,...arr2]
    console.log(arr3);
    // [1,2,3,3,4,5]
    

5.7 数组方法

5.7.1 构造函数方法
  • Array.from()

  • 将类数组或者可迭代对象转换为真正的数组

    let arrayList = {    '0':'a',    '1':'b',    '3':'c',    length:3}var arr2 = Array.from(arrayList);console.log(arr2) // ['a','b','c']
    
5.7.2 find()
  • 找出第一个符合条件的数组成员,如果有就返回,没有就返回undefined
5.7.3 findIndex()
  • 返回数组的索引。第一个符合条件的,如果没有就返回-1
5.7.4 includes()
  • 数组中是否包含给定元素 true/false

    [1,2,3,4].includes(2) //true[1,2,3,4].includes(20) //false
    

5.8 模板字符串

  • 创建新字符串的方法 “

    var str = `helloworld`
    
  • 字符串两种方法

    • startsWith():字符串是否在原来的字符串头部

      let str = 'helloworld'str.startsWith('he') // true
      
    • endsWith(): 尾部

  • repeat():将原来的字符串重复n次

    var str = 'h'str.repeat(10) // hhhhhhhhh
    

5.9 Set数据结构

  • 类似于数组,一种数据的集合,准确来说叫集合,元素不可重复

  • 创建set

    // Set本身是一个构造函数,使用new创建
    let set = new Set()
    // 也可以接受一个数组作为初始化
    let set = new Set([1,2,3,4,4])
    console.log(set)
    
  • set转换arr

    let set = new Set([1,2,3,4,4])
    var arr = [...set]
    
5.9.1 实例方法
  • add(value): 添加某个值,返回set结构本身

    const set = new Set();
    set.add(1).add(2).add(3);
    
  • delete(value):删除某一个值,返回布尔值,表示删除成功

    const set = new Set();
    set.add(1).add(2).add(3);
    set.delete(2)
    
  • has(value): 查找值,返回布尔

    const set = new Set();
    set.add(1).add(2).add(3);
    set.delete(2) // 删除 
    set.has(2) //false
    
  • clear():清空set集合

    const set = new Set();
    set.add(1).add(2).add(3);
    set.delete(2) // 删除 
    set.has(2) //false
    set.cle
    
  • forEach():对每一个成员进行操作,没有返回值

    s.forEach(value => console.log(value))
    const set = new Set([1,2,3,4,5]);
    set.forEach(value => console.log(value))
    
    

未完待续


程序员灯塔
转载请注明原文链接:JavaScript笔记&2
喜欢 (0)