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.prototypeMy.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:是否有showlet 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.利用类创建对象newvar 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.被calllet obj = {info: "我就是个普通对象"};fn.call(obj); // this----->objconsole.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===>参数1function 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使用数组传递 ;
