JS高级一

一、面向对象编程OOP

  1. 含义:以对象的功能来划分,而不是步骤
  2. 特性:封装性、继承性、动态性
  3. 类:抽象了对象的公共部分,通过类实例化一个对象
  4. 对象:一组无序的相关属性和方法的集合。万物皆对象,一个具体的事物
  5. 属性:事物的特征
  6. 方法:事物的行为

二、创建类

  1. 通过class关键字创建类,类名我们还是习惯性定义首字母大写
  2. 类里面有个constructor函数,可以接受传递过来的参数,同时返回实例对象中
  3. constructor函数, 只要new生成实例时,就会自动调用这个函数,如果我们不写这个函数,类也会自动生成这个函数
  4. 生成实例, new不能省略
  5. 最后注意语法规范,创建类, 类名后面不要加小括号,生成实例, 类名后面加小括号,构造函数不需要加function
  6. 我们类里面所有的函数不需要写function
  7. 多个函数方法之间不需要添加逗号分隔
< script>
// 1.创建类class 创建 一个明星类
class Star {
  //类的共有属性放到constructor里面
  constructor(uname, age) {
    this.uname = uname ;
    this.age = age;
  }

  //我们类里面所有的函数不需要写function,多个函数方法之间不需要添加逗号分隔
  sing () { 
    console.log('我会唱歌')
  }
  
}

// 2.利用类创建对象new
var ldh = new Star('刘德华'18);
var zxy = new Star('张学友'20);
console . log(1dh);
console. log(zxy);

</script>

三、类的继承

  1. 程序中的继承:子类可以继承父类的一些属性和方法。
class Father { }                 // 父类
class Son extends Father { }     // 子类继承父类
  1. super关键字:可以调用父类的构造函数/普通函数
  2. 子类在构造函数中使用super,必须放到this前面(必须先调用父类的构造方法,再使用子类的构造方法)
  3. 继承中,如果实例化子类输出一个方法, 先看子类有没有这个方法,如果有就先执行子类的
  4. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
class Father {
  say() {
    return ' 我是爸爸';
  }
}


class Son extends Father {
  say() {
    console.1og(我是儿子);
  }
}

var son = new Son ();
son.say();
class Person { // 父类
  constructor ( surname) {
    this. surname = surname;
  }
}

class Student extends Person {
  //子类继承父类
  constructor (surname, firstname) {
    super (surnane) ;
    // 调用父类的constructor (surname)
    this.firstname = surname;     //定义子类独有的属性
}
}

三个注意点:

  1. 在ES6中类没有变量提升,所以必须先定义类,才能通过类实例化对象
  2. 类里面的共有属性和方法一定要加this使用
  3. 类里面的this指向问题.
  4. constructor 里面的this指向实例对象方法里面的this指向这个方法的调用者

四、构造函数和原型

1. 概念
在ES6之前,对象不是基于类创建的,而是用种称为构建函数的特殊函数来定义对象和它们的特征。
创建对象可以通过以下种方式:

  1. 对象字面量
  2. new Object0
  3. 自定义构造函数

2. 构造函数
构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new 一起使用。我
们可以把对象中一些公共的属性和方法抽取出来 ,然后封装到这个函数里面。

new在执行时会做四件事情:
①在内存中创建一个新的空对象。
②让this指向这个新的对象。
③执行构造函数里面的代码,给这个新对象添加属性和方法。
④返回这个新对象(所以构造函数里面不需要return ) 。

// 利用构造函数创建对象
function Star(uname, age) { 
  this. uname = uname ;
  this.age = age;
  this.sing = function() {
    console.log( '我会唱歌' );
  }
}

var 1dh = new Star('刘德华’,18);
var zxy = new Star('张学友'19);
console .1og(1dh);
1dh.sing(); 
zxy.sing();

// 1. 实例成员就是构造函数内部通过this添加的成员uname age sing 就是实例成员,实例成员只能通过实例化的对象来访问
console . log(1dh. uname);
ldh. sing();
console. log(Star .uname);   //不可以通过构造函数来访问实例成员

// 2.静态成员在构造函数本身上添加的成员 sex 就是静态成员
Star.sex = '男';           
console . log(Star.sex);   // 静态成员只能通过构造函数来访问
console.1og(1dh.sex);      // 不能通过对象来访问

3. 构造函数的问题
构造函数方法很好用,但是存在浪费内存的问题。

4. 构造函数原型prototype

  1. 构造函数通过原型分配的函数,是所有对象所共享的。
  2. JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象。 注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
  3. 我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法。
  4. 原型是什么?
    一个对象,我们也称为prototype为原型对象。
  5. 原型的作用是什么?
    共享方法。

5. 对象原型_ proto_

  1. 对象都会有一一个属性_ proto_ 指向构造函数的 prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有_ proto_ 原型的存在。
  2. _ proto_ 对象原型和原型对象prototype是等价的。
    JS高级一_第1张图片

6. constructor构造函数

  1. 对象原型(_ proto_ ) 和构造函数的原型对象( prototype )里面都有一个属性 constructor属性, constructor我们称为构造函数,因为它指回构造函数本身。
  2. constructor主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
function Star(uname, age) {
  this. uname = uname ;
  this.age = age;
  
//很多情况下,我们需要手动的利用constructor这个属性指回原来的构造函数
// Star . prototype. sing = function() {
//    console. log( '我会唱歌' );
// };
// Star . prototype. movie = function() {
//    console . log('我会演电影');
// }

 // 如果我们修改了原来的原型对象,给原型对象赋值的是个对象,则必须手动的利用 constructor指回原来的构造函数
   Star. prototype = {
     constructor: Star,
     sing: function() {
       console.1og(我会唱歌' );
     },
     movie: function() {
       console.log( '我会演电影');
     }
}


var ldh = new Star('刘德华'18);
var zxy = new Star('张学友'19);
console .1og(Star. prototype);
console .1og(1dh._ proto__ ) ;

7. 构造函数、实例、原型对象E者之间的关系
JS高级一_第2张图片

8.原型链
JS高级一_第3张图片

9. JavaScript的成员查找机制(规则)
①当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
②如果没有就查找它的原型(也就是_ proto_ 指向的prototype原型对象)。
③如果还没有就查找原型对象的原型( Object的原型对象)。
④依此类推一直找到Object为止( null )。
⑤_ proto 对象原型的意义就在于为对象成员查找机制提供一 个向,或者说一条路线。

10. 扩展内置对象
可以通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组增加自定义求偶数和的功能。

<script>
//原型对象的应用:扩展内置对象方法
console.log(Array. prototype);
Array.prototype.sum = function() {
  var sum = 0;
  for (var i = 0; i < this.length; i++) {
    sum += this[i];
  }
  return sum;
}
var arr=[1,2,3];
console.log(arr.sum());
</script>

五、继承

1. 概念
ES6之前并没有给我们提供extends继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。

2. 借用构造函数继承父类型属性
核心原理:通过call()把父类型的this指向子类型的this ,这样就可以实现子类型继承父类型的属性。

<script>
// call方法
function fn(x, y) {
  console.1og( '我想喝手磨咖啡);
  console . log(this);
  console.1og(x + y);
}

var obj = { name: 'lfl' }

// 1. cal1() 可以调用函数
// fn. call();

// 2. call() 可以改变这个函数的this指向此时这个函数的this就指向了o这个对象
fn.call(obj, 1, 2);
</script>
<script>
//借用父构造函数继承属性

// 1.父构造函数
function Father(uname, age) {
  // this指向父构造函数的对象实例
  this .uname = uname;
  this.age = age;
}

// 2.子构造函数
function Son(uname, age, score) {
  // this指向子构造函数的对象实例
  Father . call(this, uname, age);
  this.score = score; 
}

var son = new Son ('刘德华'18, 100);
console . log(son); 
</script>

3. 借用原型对象继承父类型方法

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.1og('孩子要考试');
}

var son = new Son('刘德华'18, 100);
console. log(son);
console . log(Father .prototype);
console . log(Son. prototype . constructor);

你可能感兴趣的:(JS)