Js进阶四天
成长必经之路
目录
- 构造函数: ES5继承
- ES6类的相关
- call/apply/bind
构造函数
继承
目标: 掌握属性和方法继承
为什么要学习继承: 有的构造函数上原型对象上已经实现一部分方法; 我们需要这些方法, 就需要把这个部分功能继承过来( 内存地址上指向是同一个地址), 而不是重新再写一次;
实例属性的继承: 直接复制?
//参数1:Other构造函数内部属性即将要去到这个对象上
//参数,参数1后面的参数,就是我们自己传入的属性值!/
// Other.call(obj);
// 结论: other被某个对象打电话: 某个对象上就会有other内部的属性名和值;
实例属性的继承: call语法
// 2---------------------新的语法:一次性把对方身上所有属性全部拿过!
// call:打电话呼叫;基础语法
//
function other(house,money,car){
this.house = house;
this.money = money;
this.car = car;}
var obj = {
info:"我就是个单独对象",
};
other.call(obj,10,20,10);
// call语法规则:【需要重点记忆】
// 1.Other丞数肯定是要执行!
// 2.参数:第一个参数other执行,other内部this上的所有的属性名即将要去到这个参数上;
// 3.剩余参数,必须逗号分隔;就是oTher执行时,需要传入的实参;
console.log(obj);
实例属性的继承: call方式实现
function My(a, b, c) {
// Other.call(this) 继承对方构造函数内部的压性名
//( ,a,b,c); 自己规定内部压性值,设置为形参,没有固定!
Object.call(this, a, b, c)
//不能这样写,上面代码相当于结果下面这样结果:
// this.money = a;
// this.cars = b;
// this.house = c;
}
let m1 = new My()
console.log(m1); //My {}
let m2 = My()
console.log(m2); //undefined
继承
原型对象上的方法继承
//别人写好杓造函数+原型对象
function Other(money, cars, house) {
// 初始化属性
this.money = money;
this.cars = cars;
this.house = house;
}
Other.prototype.show = function () {
console.log(`你看老子多有钱:有钱${this.money}、有车${this.cars}、有房${this.house}`);
};
};
Other.prototype.sing - function() {
console.log(“你看老子多有钱,我会唱歌“);
};
//自己:
function My (house){
other.call(this,house);
}
方式1: 把其他构造函数的原型对象直接使用( 不可取)
function My(a, b, c) {
Object.call(this, a, b, c)
}
// 方式1,不推荐!My原型对象不要了,被重新赋值了, 指向Other原型对象;
// 原因:此时My原型对象和0ther原型对象其实公用一个原型对象:如果现在继续在
//My . prototype添加方法,无形中就给other.prototype添加新了的方法:可能出现问题!
// 不允许,你可配用你同事封装好原型对象方法,绝对不能修改同事的原型对象!
My.prototype = Object.prototype
My.prototype.abc = function () {
console.log("my自己新增的方法");
}
let m = new My(44, 55, 66)
console.log(m); //My {}
let o = new Object(77, 88, 99)
console.log(o); //Number {77}
方式2: 直接修改原型对象的proto属性值为 对方的原型对象
// -----------------------自己---------------------------
function My(a, b, c) {
Other.call(this, a, b, c)
}
//方式2:My.prototype普通对象:__proto__--->默认Object.prototype
//思路完全正确,__proto__是标准属性,不能出现在代码当中!
My.prototype.__proto__ = Other.prototype;
My.prototype.sing = function () {
console.log("我会脱衣舞"); //我会脱衣舞
}
let m = new My(10, 55, 99)
m.show()
m.sing()
let o = new other(1, 1, 1);
o.sing()
方式3: 最终方案
//方式3:
My.prototype = new Other();
My.prototype.abc = function () {
console.log("abc");
}
//测试1:是否有show
let m = new My(10, 20, 30)
m.show()
//测试2.如果我给MY.prototype新增一个方法,看Other是否 影响?
m.abc();
let o = new Other(44, 55, 66)
o.abc()
继承-示意图
ES6类
基本语法
目标: 知道什么类
概念: 将对象中公共的方法或者属性封装成一个模板 (es5中的构造函数)
作用: 创建对象
语法:
//步骤1使用c1ass关键字name就是一大类的名称,可以理解为构造函数的名称class name {
class name{}
//步骤2使用定义的类创建实例注意new关键字
var XX= new name();
注意事项:
- 通过类创建对象必须使用new关键字
- 类的命名规范与构造函数的命名规范一样(帕斯卡命名法)
- 创建对象后类名后面必须加()
constructor:构造函数
目标: 类里面添加属性和方法
- 在constructor内部添加, 相当于构造函数内部;
// 1.创建类c1ass创建一个明星类
class star {
//类的共有属性放到constructor里面
constructor (name,age) {
this.name = name;
this.age = age;
}
}
//2.利用类创建对象new
var 1dh = new star ('刘德华',18);
console. log(1dh);
- 在constructor下面直接添加方法, 无符号分隔, 不需要写function关键字
//1.创建类class创建一个类
//ES6:类 Person:后面没有()
class Person {
//构造函数:前面没有function关键词,结尾没有【,】分隔符!
constructor(name, age) {
this.name = name;
this.age = age;
}
sing() {
//方法,直接放下面写,要求和constructor一样
console.log(this.name + "会唱歌");
}
eat() {
console.log(this.name + "会干饭");
}
}
//使用:
let p = new Person("zs", 19)
console.log(p); //Person: age: 19 name: "zs"
继承
//我的:继承 extends 延伸扩展
class My extends Other {
abc() {
console.log("握手ABC的方法");
}
}
let m = new My("zs", 19)
console.log(m); //My {house: "zs", car: 19}
super的使用
- 使用场景1: 如果在子类中, 想调用父类中的方法;
// super关键字调用父类普通函数
class My extends Other {
test() {
super.show()
}
show() {
console.log("我是 类的方法啊");
}
}
let m = new My("zs,19")
console.log(m); //My {house: "zs,19", car: undefined}
//需求:继承别人方法和属性,现在想在test内部,调用下other原型链上 show方法;
//细节:super关键词,帮助我们直接调用 被继承原型对象上的同名方法!
- 使用场景2: 在子类的构造函数内部定义自己的属性时, 需要用super调用, 把父类的构造函数内参数传入, 且必须写在子类this的前面; 不然会报错
// 2.设置自己构造函数;设置自己属性
class My extends Other {
//规定:extends帮助内部 设置形参 失效;
//1.需要我们单独设置设置形参 2.super方法最终调用 必须在当前结构函数内部this之前;
//extends继承了属性,没有属性值;
constructor(a, b, c, name, age) {
super(a, b, c);
this.name = name;
this.age = age; //不可避免要写自己的属性,下面自己原型上方法肯定需要自己的属性
}
}
let m = new My(10, 20, 99, "zs", 29);
console.log(m); //My {house: 10, car: 20, name: "zs", age: 29}
补充知识
// function关键字声明函数: this可以用!看清楚是怎样调用的方式! 谁调用就是谁!
function fn() {
this.a = 10;
this.b = 20;
}
// 1.常规 ===> window.fn(); this--->widnow;
fn();
console.log(window);
// 2.内部this--->本次实例化对象
let res = new fn();
console.log(res); //fn { a: 10, b: 20 }
// 3.被call
let obj = {
info: "我就是个普通对象"
};
fn.call(obj); // this----->obj
console.log(obj); //{info: "我就是个普通对象", a: 10, b: 20}
console.log(obj.a); //10
// --------箭头函数:没有this!
// 没有this:内部没有内置变量this,this用的外面的this;
// 规则:箭头函数不看调用,看在出生哪个作用域创建,
改变this指向
call方法的使用
语法:
函数.call();
作用: 函数在该次的调用的时候, 其函数内部this 指向 我们指定参数的那个对象; 这个函数要执行的 !
参数: 参数1, 函数fn内属性名即将要去到这个参数上;
//call改变 function形式 内部this指向:
//语法:fn.call(参数1);
// fn肯定会执行
// 函数内部this在本次调用中,this===>参数1
function fn() {
this.a = 10;
this.b = 20
} //function My() {Other.My(this)}
let arr = []
fn.call(arr)
//场景:用于ES5 构造函数内部属性继承!
apply方法
作用: 1. 函数在该次的调用的时候, 其函数内部this 指向 我们指定参数的那个对象;
- 这个函数要执行的!
参数: 1. this 指向 我们指定
参数
的那个对象- fn要执行的时候, 把
参数 作为一个数组传入
;
- fn要执行的时候, 把
// apply: 作用和call一样!
// 语法:函数.apply(参数1)
// 在本地调用中,把函数内部this上属性,给了参数1;
// 相同:call 与 apply 参数1:内部属性即将要去到新对象!前面函数肯定要执行!
// 不同点:call 后面参数 【,】 隔开!
// apply 后面只有一个参数,把即将要传入实参,形成为数组!
// call演示:
function fn(a, b) {
this.a = a;
this.b = b;
}
let obj1 = {
info: "我是普通对象obj1"
}
fn.call(obj1, 99, 88);
console.log(obj1);
// apply演示:
let obj2 = {
info: "我是普通对象obj2"
}
fn.apply(obj2, [77, 66]);
console.log(obj2);
bind方法
bind() 方法不会调用函数
,但是能改变函数内部this 指向,返回的是原函数改变this之后产生的新函数如果只是想改变 this 指向, 并且不想调用这个函数的时候, 可以使用
bind
```javascript //bind; //知识改变函数内部this指向,不会让函数执行! //内部已经在强制性滚顶了,不管接下来该函数如何被调用!
//语法:函数.bind(参数) //返回:返回新的函数(和旧的函数长一样),内部this已经被我们固定了!
-
Swiper插件的优化: 右侧点击功能, 下面这样写会构成`闭包! 一个功能就是一个闭包`! 多个功能就是多个闭包!
```javascript
//bind;
//知识改变函数内部this指向,不会让函数执行!
//内部已经在强制性滚顶了,不管接下来该函数如何被调用!
//语法:函数.bind(参数)
//返回:返回新的函数(和旧的函数长一样),内部this已经被我们固定了!
call / apply/ bind 方法异同点
this: 大白话
- 一般情况: 谁调用就是谁 !
- 函数遇见call、 apply、 bind: 遇见第一参数是谁就是谁!
- 相同点: 这样的调用方式, 都可以把本次调用的内的this 改变函数内部this指向!
不同点
- call 和 apply 会调用执行函数! bind 不会执行函数!
- call 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递 ;