JS原型和继承、this指向

(一)原型

1.创建对象

自定义构造函数

function 构造函数名(参数...){
 this.key = value;
 .......
}

命名规范
构造函数名首字母要大写 帕斯卡(每个单词首字母大写) 驼峰(从第二个单词开始首字母大写)。

new关键字创建对象

var 对象名 = new 构造函数名(实参...);

构造函数和普通函数:

  • 相同点
    • 都是函数
  • 不同点
    • 构造函数通过new关键字调用
    • 普通函数直接调用

2.实例对象和原型

原型就是一个对象,原型一直都在。

1)获取原型语法:
构造函数名.prototype

2)原型作用:
节省内存。 因为原型中存放的成员(属性或方法),都可以被相关的构造函数所创建的对象共享

3)找原型:
首先,会从对象本身中去找;
若对象中,找不到,则会通过__proto__所提供的原型地址,找原型;
去原型中查找。

代码举栗:

 // 学生类→ 构造函数
 function Student(name, age, gender) {
   // 属性
   this.name = name;
   this.age = age;
   this.gender = gender;
   // this.type = '学生'
 }

 // 获取原型
 // 每一个函数都有一个对应的原型
 var yx = Student.prototype;
 // 对象.key = value
 // 方法
 yx.sayHi = function () {
   // 方法内部:this 代表的是调用方法的对象
   console.log('我叫什么' + this.name)
 };
 yx.writeCode = function () {
   console.log('我会写code');
 }
 yx.type = '学生';

 // 创建对象
 var zs = new Student('张三', 10, '男');
 // 创建对象
 var ls = new Student('李四', 11, '男');
 // 创建对象
 var ww = new Student('王五', 17, '女');

(二)原型继承

原型继承实现时必会有下面两句代码:

  • 先更改子类的原型prototype指向一个new 父类() 对象。
    • 子类.prototype = new 父类();
  • 再给子类的原型设置一个constructor指向子类
    • 子类.prototype.constructor = 子类
//  用于设置原型
Employee.prototype = new Person()
//  设置原型的构造器
Employee.prototype.constructor=Employee

代码举栗:

 // 人类 → 父类
 function Person() {
   this.name = '名字';
   this.age = 10;
   this.gender = '男';
 }
 Person.prototype.sayHi = function () { console.log('你好'); };
 Person.prototype.eat = function () { console.log('我会吃。。。'); };
 Person.prototype.play = function () { console.log('我会玩'); };

 // 学生类 → 子类
 function Student() {
   this.stuId = 1000;
 }
 // 子类的原型prototyp指向父类的一个实例对象
 Student.prototype = new Person();
 // 添加一个constructor成员
 Student.prototype.constructor = Student;

 // 如何实现原型继承:
 // 给子类的原型prototype重新赋值为父类的一个实例对象。
 // 利用了原型链上属性或方法的查找规则。

 // 创建一个学生对象
 var stu1 = new Student();
 console.log(stu1.constructor)

(三)借用继承

1.call方法

  • 语法:函数名.call(调用者,函数实参,函数的实参...);
  • 作用:该函数会立即执行,函数体内的this在被call时,this指向调用者。

2.用call方法实现继承

 // 人类 → 父类
 function Person(name,age,gender) {
   this.name = name;
   this.age = age;
   this.gender = gender;
 }
 Person.prototype.sayHi = function () { console.log('你好'); };
 Person.prototype.eat = function () { console.log('我会吃。。。'); };
 Person.prototype.play = function () { console.log('我会玩'); };

 // 学生类 → 子类
 function Student(name,age,gender,stuId) {
   // this关键字代表谁,代表的是一个学生对象,当前创建的对象 stu1 ,stu2
   // var obj = this;
   //【借用继承】
   // Person.call(obj,name,age,gender);
   Person.call(this,name,age,gender);
   this.stuId = stuId;
 }

 // 创建第一个学生对象
 var stu1 = new Student('张三',10,'男',10086);
 // 创建第二个学生对象
 var stu2 = new Student('李四',11,'女',10010);

(四)组合继承

 // 人类 → 父类
 function Person(name,age,gender) {
   this.name = name;
   this.age = age;
   this.gender = gender;
 }
 Person.prototype.sayHi = function () { console.log('你好'); };
 Person.prototype.eat = function () { console.log('我会吃。。。'); };
 Person.prototype.play = function () { console.log('我会玩'); };

 // 学生类 → 子类
 function Student(name,age,gender,stuId) {
   //【借用继承】
   Person.call(this,name,age,gender);
   this.stuId = stuId;
 }

 // 【原型继承】
 Student.prototype = new Person();
 Student.prototype.constructor = Student;

 // 创建第一个学生对象
 var stu1 = new Student('张三',10,'男',10086);
 // 创建第二个学生对象
 var stu2 = new Student('李四',11,'女',10010);

(五)函数内部this指向情况总结

1.普通函数中的this

普通函数内部的this指向window

function fn() {
    console.log(this); //window
}
fn();

直接调用的函数就是普通函数

var obj = {
  getSum: function () {
    console.log(this); //执行obj。输出obj
    function fn2() {
      console.log(this); //window
    }
  }
};
obj.getSum();

2.定时器中的this

只要用到定时器,setTimeout和setInerval都默认指向window

3.构造函数

this指向当前创建的对象

//匿名函数一般首字母大写
function Person() {
  this.name = 'zhang';
  this.age = 10;
  console.log(this); //Person{}
}
new Person();

4.对象的方法

this指向调用者

5.事件处理程序

this默认指向事件源

document.onclick = function () {
  console.log(this); //document
}

(六)改变this的指向

1.call方法

  • 语法:函数名.call(调用者,参数1,参数2...);
  • 作用:函数被借用时会立即执行,并且函数体内的this会指向借用者或调用者
    函数内部this指向谁,看函数在这一次的调用情况。
function fn(a, b) {
  this.name = a;
    this.age = b;
}
fn(10, 20); //指向window,window中增加name和age
var obj = {};
fn.call(obj, 'zhang', 10); //obj中增加name和age,仅在这一次增加

2.apply方法

  • 语法:函数名.apply(调用者,参数1,参数2...);
  • 作用:函数被借用时,会立即执行,并且函数体内的this会指向借用者或调用者
 function fn(name, age) {
   this.name = name;
   this.age = age;
 }

 // 对象字面量
 var obj = {};
 fn.apply(obj, ['李四', 11]);

3.bind方法

  • 语法:函数名.bind(调用者,参数1,参数2...);
  • 作用:该函数被借用时,不会立即执行,而是返回一个新的函数,需要自己手动调用新函数
 function fn(name, age) {
   this.name = name;
   this.age = age;
 }

 // 对象字面量
 var obj = {};
 fn.bind(obj, '李四', 11);

(七)函数作为函数的参数

  • 把一个函数B当做实参,传递给另一个函数的A的形参,并在函数A内部调用
    实参可以是任何类型的数据。(数字、字符串、布尔值、数组、对象、函数、undefined)。

函数也是一种数据类型,格式是function

你可能感兴趣的:(JS原型和继承、this指向)