JavaScript高级

邮差的信 提交于 2019-11-29 05:03:18

1.面向过程与面向对象

 1.1面向过程
  面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了。
  面向过程是 实现代码逻辑的 步骤,主要是把重心点放在实现功能上,不太去考虑封装
  优点: 效率高,但是维护起来太麻烦  
  1.2面向对象
  面向对象是把事务分解成一个个对象,然后由对象之间分工合作。
  主要的重心点,先放在功能模块的划分,然后想着什么功能模块可以去进行复用(可以进行抽取)
  优点: 会让我们功能具备模块化开发,一个模块就负责一个功能,后续方便我们的维护
  三大特性:继承性、封装性、多态性(抽象性)
 

2.对象与类

  2.1 对象 
  对象是由属性和方法组成的:是一个无序键值对的集合,指的是一个具体的事物
  属性:事物的特征,在对象中用属性来表示(常用名词)
  方法:事物的行为,在对象中用方法来表示(常用动词)
  创建对象的两种方法
    1.字面量创建对象    
      var ldh = {
      name: '刘德华',
      age: 18
      }
      console.log(ldh);
 
 
    2.构造函数创建对象
      function Star(uname,age){
        this.uname = name;
        this.age = age;
      }
      var ldh = new Star('刘德华',18); //实例化对象
      console.log(ldh);
 2.2 类 
  在 ES6 中新增加了类的概念,可以使用 class 关键字声明一个类,之后以这个类来实
  例化对象。类抽象了对象的公共部分,它泛指某一大类(class)对象特指某一个,
  通过类实例化一个具体的对象
   
  2.2.1创建类
     语法:  
       //步骤1 使用class关键字
    class name {
    // class body
    }
    //步骤2使用定义的类创建实例 注意new关键字
    var xx = new name();
  2.2.2类创建添加属性和方法  
    // 1. 创建类 class 创建一个类
    class Star {
      // 类的共有属性放到 constructor 里面 constructor是 构造器或者构造函数
      constructor(uname, age) {
      this.uname = uname;
      this.age = age;
      }//‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐>注意,方法与方法之间不需要添加逗号
      sing(song) {
      console.log(this.uname + '唱' + song);
      }
    }
  // 2. 利用类创建对象 new 实例化
  var ldh = new Star('刘德华', 18);
  console.log(ldh);   // Star {uname: "刘德华", age: 18}
  ldh.sing('冰雨');     // 刘德华唱冰雨
 
  注意点:
    1. 通过class 关键字创建类, 类名我们还是习惯性定义首字母大写
    2. 类里面有个constructor 函数,可以接受传递过来的参数,同时返回实例对象
    3. constructor 函数 只要 new 生成实例时,就会自动调用这个函数, 如果我们不写这个函数,类也会自动生成这个函数
    4. 多个函数方法之间不需要添加逗号分隔
    5. 生成实例 new 不能省略
    6. 语法规范, 创建类 类名后面不要加小括号,生成实例 类名后面加小括号, 构造函数不需要加function
 
 2.2.3 类的继承
  语法 :   class Father { }; // 父类
      class Son extends Father { } // 子类继承父类 extends
  示例 :   
      class Father {
        constructor(surname) {
        this.surname= surname;
        }
        say() {
          console.log('你的姓是' + this.surname);
        }
      }
      class Son extends Father{     // 这样子类就继承了父类的属性和方法
      }
      var damao= new Son('刘');
      damao.say(); // 输出结果是   你的姓是刘
  
  子类使用super关键字访问父类的方法
   
    //定义了父类
    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调用了父类中的构造函数
      }
    }
    var son = new Son(1, 2);
    son.sum();     //结果为3
 
  注意:
    1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
    2. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
    3. 如果子类想要继承父类的方法,同时在自己内部扩展自己的方法,利用super 调用父类的构造函数,super 必须在子类this之前调用
 
 2.2.4 时刻注意this的指向问题
    我们在类中,去使用属性或者是调用方法千万不要忘记了用 this,
    需要去关注的就是this的指向问题:
        默认情况下,类中的this都指向的是当前实例化的对象,
        除非 绑定事件之后this指向的就是触发事件的事件源
 

3.构造函数和原型

  3.1 静态成员和实例成员

    实例成员 :实例成员就是构造函数内部通过this添加的成员,实例成员只能通过实例化的对象来访问

     以下代码里的 uname  age sing就是实例成员

function Star(uname, age) {
     this.uname = uname; 
     this.age = age; 
     this.sing = function() { 
            console.log('我会唱歌'); 
      } 
}
var ldh = new Star('刘德华', 18); 
console.log(ldh.uname);    //实例成员只能通过实例化的对象来访问    

 

     静态成员 :在构造函数本身上添加的成员 静态成员只能通过构造函数来访问    在ES5中只要被static修饰的属性和方法都是静态成员

     下列代码中 sex 就是静态成员

   

function Star(uname, age) { 
         this.uname = uname; 
         this.age = age; 
         this.sing = function() { 
               console.log('我会唱歌'); 
         } 
}
Star.sex = '男'; 
var ldh = new Star('刘德华', 18);
 console.log(Star.sex);          //静态成员只能通过构造函数来访问

  3.2构造函数的问题

    存在浪费内存的问题

    

function Star(uname , age) {
      this.uname = uname;
      this.age = age;        
      this.sing = function(){
             console.log('我会唱歌')
      }
}
var ldh = new Star("刘德华",18);
var shuji= new Star("书记",22);
ldh.sing();
shuji.sing();

   以上代码在调用sing方法时都会在内存开辟一个新的空间,如果有多个对象来调用sing方法就会占用过多内存,所以我们就用到了构造函数的原型 prototype。

  3.3 构造函数原型prototype

    构造函数通过原型分配的函数是所有对象所共享的。

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

     我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。

     构造函数.prototype就可以获取原型对象

function Star(uname, age) { 
         this.uname = uname; 
         this.age = age;
 }
Star.prototype.sing = function() {
         console.log('我会唱歌'); 
}
var ldh = new Star('刘德华', 18); 
var zxy = new Star('张学友', 19); 
ldh.sing();  //我会唱歌 
zxy.sing();  //我会唱歌

 

   3.4 对象原型

    实例化对象都会有一个__proto__属性指向构造函数的原型对象,而我们的实例化对象可以使用对象原型的属性和方法就是因为有__proto__属性的存在

    实例化对象.__proto__ ===  构造函数.prototype

    它们的三角关系如下图:

      

    __proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象prototype

   3.5 constructor构造函数

     对象原型( __proto__)和构造函数(prototype)原型对象里面都有一个属性constructor 属性

     constructor 我们称为构造函数,因为它指回构造函数本身。

     constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。

    

    如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
function Star(uname, age) {
  this.uname = uname;
  this.age = age;
}
// 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
Star.prototype = {
// 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
  constructor: Star, // 手动设置指回原来的构造函数
  sing: function() {
    console.log('我会唱歌');
  },
  movie: function() {
    console.log('我会演电影');
  }
}
var zxy = new Star('张学友', 19);
console.log(zxy)

   3.6 原型链和查找机制

    每一个实例对象又有一个proto属性,指向的构造函数的原型对象,构造函数的原型对象也是一个对象,也有proto属性,这样一层一层往上找就形成了原型链。

    

  

     查找机制:

      当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性,如果自身有,就有自身的属性和方法。

      如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。

      如果还没有就查找原型对象的原型(Object的原型对象)。依此类推一直找到 Object 为止(null)。

      如果找到尽头(null)都没找到,是属性则返回undefined,是方法则报错

   

  3.7 原型对象中this的指向

    构造函数中的this和原型对象的this,都指向我们new出来的实例对象

   3.8 通过原型对象为数组扩展内置方法

    

var arr = [3,6,9,8,5]
arr.prototype.sum = function() { 
        var sum = 0; 
        for (var i = 0; i < this.length; i++) {
                  sum += this[i]; 
        }
        return sum; 
};              //此时数组对象中已经存在sum()方法了 可以用于数组.sum()进行数据的求和

  

4.继承

  4.1 call()

    call()可以调用函数   可以修改this的指向,使用call()的时候,()里的第一个参数是修改的this指向,参数2 参数3 使用逗号隔开

    

function fn(x, y) {
     console.log(this); 
     console.log(x + y); 
} 
var o = { 
    name: 'andy' 
};
fn.call(o, 1, 2); //调用了函数此时的this指向了对象o, 

    4.2 构造函数继承属性   

    1. 先定义一个父构造函数
    2. 再定义一个子构造函数
    3. 子构造函数继承父构造函数的属性(使用call方法)
// 1. 父构造函数 
function Father(uname, age) { 
// this 指向父构造函数的对象实例
      this.uname = uname; 
      this.age = age; 
}
// 2 .子构造函数 
function Son(uname, age, score) {
     // this 指向子构造函数的对象实例 
//3.使用call方式实现子继承父的属性 
      Father.call(this, uname, age);
      this.score = score; 
}
var son = new Son('刘德华', 18, 100); 
console.log(son);

   

   4.3 借用原型对象继承方法

    (1). 先定义一个父构造函数
    (2). 再定义一个子构造函数
    (3). 子构造函数继承父构造函数的属性(使用call方法)
// 1. 父构造函数 
function Father(uname, age) { 
// this 指向父构造函数的对象实例 
  this.uname = uname; 
  this.age = age; 
}
Father.prototype.money = function() { 
  console.log(100000); 
};
 //子构造函数
  function Son(uname, age , score){ 
    // this 指向子构造函数的对象实例
    Father.call(this, uname, age);
    this.score = score;
  };
// Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对 象,父原型对象也会跟着一起变化 
Son.prototype = new Father(); 
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数 
Son.prototype.constructor = Son; 
// 这个是子构造函数专门的方法 
Son.prototype.exam = function() { 
  console.log('孩子要考试'); 
}
var son = new Son('刘德华', 18, 100); 
console.log(son);

  

 5.ES5新增方法

  5.1 forEach()遍历数组  没有返回值

    array.forEach(function(value , index , array){....})

    value是每个数组元素

    index是每个元素索引值

    array是当前数组

  5.2 filter()筛选数组  其实也会遍历数组

    array.filter(function(value , index , array){

      return  条件表达式

    })

    返回的是一个新数组  括号跟的参数都是一样的

  5.3 some()   查找数组中是否有满足条件的元素  其实也会遍历数组

    array.some(function(value , index , array){

      return  条件表达式

    })

     返回值是布尔值,只要查找到第一个满足条件的元素就会终止循环 效率高  

 

   5.4 trim方法去除字符串两端的空格

    字符串的特性 不可变性

var str = ' hello ' ;
console.log(str.trim())  //hello 去除两端空格 
var str1 = ' he l l o ' ;
console.log(str1.trim())  //he l l o 去除两端空格

  5.5 获取对象的属性名 

    Object.keys(对象) 获取到当前对象中的属性名 ,返回值是一个数组

var obj = { 
    id: 1, 
    pname: '小米', 
    price: 1999,
    num: 2000 
};
var result = Object.keys(obj);
console.log(result)   //返回的新数组[id,pname,price,num]

  5.6 Object.defineProperty设置或修改对象中的属性

Object.defineProperty(对象,修改或新增的属性名,{ 
  value:修改或新增的属性的值, 
  writable:true/false,  //如果值为false 不允许修改这个属性值 
  enumerable: false,    //enumerable 如果值为false 则不允许遍历 
  configurable: false   //configurable 如果为false 则不允许删除这个属性 属性是否可以被删除或是否可以再次修改特性 
})

 

 

 

 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!