JS高级11.2-11.6

自由变量:函数内部使用外部的变量,这个变量就是自由变量。
注:跨域的变量都是自由变量,即变量声明和使用不在一个作用域。

递归:
定义:自己调用自己。
注:一定要有结束(出口)。

所有的编程语言通过编程范式分为:
命令式编程——分为面向过程式编程和面向对象式编程
声明式编程

自动拆箱,自动装箱 内置对象(包装类):
创建构造函数:和普通函数的书写方式一样(命名以大驼峰方式)
基本数据类型:字符串可以直接使用String的方法和属性
基本数据类型:数值不可以直接使用toString的方法
原因:数值分整型和浮点型(小数)
123.toString() 123后面的点,会被识别为小数点,不会装箱为对象
解决方式为:
(123).toString();
自动拆箱(new后面跟的就是拆开后的数据类型)
let num = new String(456);
num.abc = 123;
console.log(num.abc, typeof num.abc);//123 ‘number’
console.log(num - 1);//455
console.log(num + 1);//4561

面向对象(Oriented Object): (Analysis Design分析设计JAVA)
面向过程:把解决问的方法和步骤,一步一步写出来(JS代码)。
面向对象:把解决问的方法和步骤中涉及到的属性和方法,封装成一个构造函数(对象)。

类(class):具有相同的属性和行为的一组对象的抽象,既对于一类对象的抽象描述;
使用时,就像是一类事物的生产模板,可以用类来产出任意数量的实际对象。

类与对象的关系:
类是对象的抽象,对象是类的实例。

// let f71 = new f70();
// console.log(f71);

// let num = 123;
// console.log(num,num.length,typeof num);

let f70 = num.toString();
console.log(f70,typeof f70);

基本数据类型:字符串可以直接使用String的方法和属性
基本数据类型:数值不可以直接使用toString的方法
原因:数值分整型和浮点型(小数)
//自动拆箱(new后面跟的就是拆开后的数据类型)
let num = new String(456);
num.abc = 123;
console.log(num.abc, typeof num.abc);//123 ‘number’

console.log(num - 1);//455
console.log(num + 1);//4561

构造函数:
先创建一个构造函数(命名以大驼峰命名法)
函数内自动会创建一个叫this的对象
函数内的实参和形参的作用就是赋值(中间以=来赋值,如:this.name = name;)
如果没有return,函数内会自动补充一个return,返回的是this这个对象
如果返回的是基本数据类型,不会影响,继续返回this这个对象;如果返回的是引用数据类型,则返回的是这个引用数据

调用构造函数,就是传参数
格式:let stu1 = new Students(“xiaoguo”,18,“male”,“50kg”);(传的参数要跟上面的值一一对应)
function Students(name,age,gender,weight){
// let this = {}
this.name = name;
this.age = age;
this.gender = gender;
this.weight = weight;
// return this; //默认
// return [123]; //有效
// return 123; //无效
}
let stu = new Students();

new 一个实例
1.this的空对象
2.this的"proto"指向"类.prototype"
3.执行代码(给this添加属性和方法)
4.ruturn this(即返回对象给实例)
注:手动更改返回值,更改基本数据类型无效。更改引用值有效。

ES5中打印类,则会把所有的function里的东西打印出来;而ES6中方法不会被打印出来,但调用的时候也可以使用,这是代码进阶了,不需要占空间导致卡顿。

ES6 类 语法糖:ES6的书写方式
注:类似封装一个构造函数

class Students {
    //constructor 构造器
    constructor(name, age, gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    sayhello() {
        console.log("hello", this.name);
    }
}
let stu = new Students("z3", 18, 180);
console.log(stu.name);
stu.sayhello();
stu.haha();

//prototype建立了一个公有的属性,不需要占空间,但是能被调用到数据。
Students.prototype.banjiName = “f70”;
let stu = new Students(“xiaomimi”, 18, “male”);

let stu1 = new Students(“xiaomim”, 18, “male”);
let stu2 = new Students(“xiaomi”, 18, “male”);

stu.rich = “true”;
// 在调用时,如果没有__proto__属性,则后面再调用时获取不了值
console.log(stu.rich); //true
console.log(stu1.rich); //un
console.log(stu2.rich); //un

// 如果有__proto__属性,则只要调用构造函数的所有都可以调用这个属性,在当前构造函数中创建了一个公有的区域
stu.proto.rich = “true”;
console.log(stu.rich); //true
console.log(stu1.rich); //true
console.log(stu2.rich); //true

// prototype和__proto__建立的是同一个公有区域,只是前面调用的方式不一样

let stu4 = new Students();
// ES5可以使用普通函数调用方式,ES6会报错,提示调用前加new
let stu5 = Students();

/*
私有:
this.xxx = xxx
this.xxx = function (){}

公有:
类.prototype.xxx = xxx
类.prototype…xxx = function (){}
实例.proto.xxx = xxx
实例.proto…xxx = function (){}

注:同类别的实例对象可以使用公有的属性和方法
*/

typeof 类 ——function
注:类就是函数

普通函数和构造函数本质区别:调用方式
1.普通函数: 函数名()
2.构造函数: new 函数()
3.类: new 类名()

[this指向]:
1.普通对象,谁调用就指向谁
2.构造函数中的this,指向的是实例化对象
3.监听器中的this,指向的是绑定事件的节点
4.普通函数中的this,指向的是window,var声明可以把window内的值更改
注:严格模式下(在函数第一行如果有"use strict",即为严格模式),var声明也无效,都指向的是undefined
5.箭头函数中this的指向,取决于所处环境;箭头函数没有自己的arguments和this

书写例子:

document.addEventListener("click", function () {
    new Qiu(shuZi(100,200), `rgba(${shuZi(0,255)}, ${shuZi(0,255)}, ${shuZi(0,255)}, 0.5)`, shuZi(0,500), shuZi(0,1200));
})
let divEle = document.getElementsByClassName("lol")[0];
class Qiu {
    constructor(width,bgc, top, left) {
        this.width = width;
        this.height = width;
        this.backgroundColor = bgc;
        this.top = top;
        this.left = left;
        this.node = document.createElement("div");
        this.init();
    }
    init(){
        this.show();
    }
    show() {
        // v1.0
        /* this.node.style.width = this.width + "px";
        this.node.style.height = this.height + "px";
        this.node.style.backgroundColor = this.backgroundColor;
        this.node.style.position = "absolute";
        this.node.style.borderRadius = "50%";
        this.node.style.top= this.top + "px";
        this.node.style.left = this.left + "px";
        divEle.appendChild(this.node) */
        // v2.0 简写方式
        Object.assign(this.node.style,{
            width:this.width+"px",
            height:this.height+"px",
            backgroundColor:this.backgroundColor,
            top:this.top+"px",
            left:this.left+"px",
            position:"absolute",
            borderRadius:"50%",
        },divEle.appendChild(this.node))
    }
}

改变this的指向:
例子:

function f70(){
    this.name ="a";
    this.say = function(weight,height){
        console.log(this.name,weight,height);
    }
}
let stu1 = new f70;
let stu2 = {
    name:"xiaoguo"
}
stu1.say();//a undefined undefined

// 改变this的指向
// 类名.方法名.call(this指向的地方,"第一个参数","第n个参数");
stu1.say.call(stu2,"60kg","175");// xiaoguo 60kg 175
// 类名.方法名.apply(this指向的地方,["第一个参数","第n个参数"]);//参数需要以数组的方式传输
stu1.say.apply(stu2,["70kg","180"]);//zhixiang.js:4 xiaoguo 70kg 180
// 类名.方法名.bind(this指向的地方,"第一个参数","第n个参数");//返回是一个函数;需要接收,然后调用,才执行
let  xiaoguoH=stu1.say.bind(stu2,"80kg","190");// xiaoguo 80kg 190
xiaoguoH();

原型链:
let fn = new Function();
执行时,{如果fn.方法名,如果本身没有方法—>原型链—>{}也是Object—>null}
如果以上都没有则会报错
每个函数都有一个prototype属性叫原型

console.log(Function.prototype); //{}
console.log(fn.prototype); //constructor
fn.__proto__;//原型链
fn.__proto__.__proto__;//{}
fn.__proto__.__proto__.__proto__;//null

原型链:
1、找自身的属性,如果没有做第2步
2、在原型找属性,如果没有做第3步
3、在原型的__proto__找属性

封装、继承、多态[面向对象的三大特征]:
1.【封装】

ES5		构造函数添加属性和方法
function F70(name) {
     this.name = name;
 }
F70.prototype.say = function() {
     console.log(this.name);
 }

ES6		属性和方法封装成一个对象
class F70 {
     constructor(name) {
         this.name = name
     }

     say() {
         console.log(this.name);
     }
 }

2.【继承】inherit

ES5:
function Father(firstName, lastName, money) {
    this.lastName = lastName;
    this.firstName = firstName;
    this.money = money;
}

let F1 = new Father(1, 2, 100);
console.log(F1.money);//100
Son.prototype.gender = true;
Object.assign(Son.prototype, F1)

function Son(age) {
    this.age = age;
}

let S1 = new Son(80);
console.log(S1.age);//80
console.log(S1.money);//100
console.log(S1.gender);//true

ES6:
class Father {
    constructor(name, age, money) {
        this.name = name;
        this.age = age;
        this.money = money;
    }
}
//继承就是在class Son后添加需要被继承的函数名称extends Father
class Son extends Father {
    constructor(name, age, money) {
//如果要继承,要把需要继承函数中的所有参数都写出来;super必须写在this之前
        super(name,age,money);
        this.name = name;
        this.age = age;
    }
}

let S1 = new Son("z3", 12, 100);
console.log(S1.money);//100

上方ES6中实现继承转换成ES5解析步骤:

function GraFather() {
    this.house = 998;
}

GraFather.prototype.tiao = function () {
    console.log("haihai");
}

function Father() {
    this.age = 18;
    this.house1 = GraFather;
    this.house1();
    delete this.house1;
}

Father.prototype.say = function () {
    console.log("hello");
}

function Son() {
//在函数建立时,会创建一个this{},此时就会在this{}中添加一个this.age1=Father;
//但是在代码中有跟Father重名的构造函数,所以Father就是一个函数,当执行后,就会
//执行当前函数的内容,如果其中有this,那么this的指向也是当前Son的实例化对象,执行
//完后,我们就需要把当前的this删除,这样就实现了继承。  
    this.age1 = Father;
    this.age1();
    delete this.age1;
    this.gender = true;
}

let F1 = new Son();

//本来在Son构造函数中没有say方法,就会指向Son的上面的原型链,如果原型链中没有就
//指向上面{}(Object)中是否有say方法,但执行当前步骤后,把son指向上面的原型链,
//原型链指向上面的{}的指向改成了Father的原型链,如果Father的原型链中也没有此方
//法,才找到Father的原型链指向上面的{},如果都没有才报错;如果有,则执行此方法。
Son.prototype.__proto__ = Father.prototype;
Father.prototype.__proto__ = GraFather.prototype;

F1.say();//hello
F1.tiao();//haihai
console.log(F1.age);//18
console.log(F1.house);//998

3.【多态】
简单概况:(同一个模具,生产出不同的产品)
同一个构造函数或类,实例化出不同的对象(根据参数不同)
不同的实例对象,调用同一方法,得到不同的结果

class Students {
     constructor(name, age, gender) {
         this.name = name;
         this.age = age;
         this.gender = gender;
     }
     hello(place){
         console.log(this.name,place)
     }
 }
let stu1 = new Students("z3", 17, "male");
let stu2 = new Students("l4", 18, "female");
let stu3 = new Students("w5", 19, "male");
stu1.hello("cd");//"z3","cd"
stu2.hello("cc");//"l4","cc"
stu3.hello("cb");//"w5","cb"

【补充内容:扩展】

let obj = {
    name: "z3"
};

obj.age = 123;

Object.defineProperty(obj, "gender", {
    value: "male",//给添加的属性gender添加内容
    writable:true,//可修改内容(默认值false)
    enumerable:true,//可改变、可遍历(默认值false)
});

console.log(obj);
obj.gender = "female";
console.log(obj);

// for(let item of obj){
//     console.log(item);//会出现报错(枚举),因为它不是数组
// }

for(let item  of  Object.keys(obj)){
    console.log(item);//name,age,gender
}

两种方法只能选择一种

let obj = {
    name: "z3"
};
let age = 0;
Object.defineProperty(obj, "cc", {
    // 属性被赋值时或更改,触发set方法
    // 属性被使用时,触发get方法
    
    //value是用户给的值
    set(value){
        if(value>40){
            age = 19;
        }else{
            age = 18;
        }
    },
    get(){
        return age;//把结果反馈给cc
    }
});

console.log(obj.cc);//0
obj.cc = 45;
console.log(obj.cc);//18
obj.cc = 35;
console.log(obj.cc);//19

【深拷贝、浅拷贝】

…的功能:
功能1拆分:批量修改和赋值()
功能2整合:不定参数

浅拷贝:共用一个地址,因此其中一个更改,另一个也会发生改变。
数组版:

let arr = [1,2,3];
let arr2 = arr;//把地址给arr2
arr[2] = "a";
console.log(arr2);//[1,2,"a"]
console.log(arr);//[1,2,"a"]

对象版:

let obj1 = {
    name:1,
    age:2
}

let obj2 = obj1;
obj1.name = "a";
console.log(obj2.name);//a

深拷贝:不是一个地址,因此其中一个更改,另一个不会发生改变。
数组版:

let arr = [1,2,3];
let arr2 = arr.slice(0);——let arr2 = [...arr];//返回一个新的数组,地址更改了
arr[2] = "a";
console.log(arr2);//[1,2,3]
console.log(arr);//[1,2,"a"]

对象版:

let obj1 = {
    name:1,
    age:2
}

let obj2 = {...obj1};
obj1.name = "a";
console.log(obj2.name);//1

H5 API应用进程(程序)接口:
A:Application应用;P:Process进程(程序);I:Interface接口;

网页视频的功能:

let v1 = document.getElementsByTagName("video")[0];
let divEle = document.getElementsByClassName("contaniu")[0];
let divEle1 = document.createElement("div");
let index = false;

divEle.addEventListener("click", function (e) {
    let event = e || window.event;
    let divEle2 = document.getElementsByClassName("guangGao")[0];
    if (event.target.value == "播放") {
        // play是设置视频播放
        v1.play();
        if(index){
            divEle2.remove();
        }
        index = false;
        
    } else if (event.target.value == "暂停") {
        // pause是设置视频暂停播放
        v1.pause();
        divEle1.setAttribute("class", "guangGao");
        divEle1.innerHTML = `
        这是一个小广告
        <span class="sc">x</span>
        `;
        divEle.appendChild(divEle1);
        index = true;

    } else if (event.target.className == "sc") {
        divEle2.remove();
        index = false;

    } else if (event.target.value == "音量") {
        // volume是设置视频播放声音(取值0-1,0是静音,1是最大音量)
        v1.volume = 0.3;

    } else if (event.target.value == "快进5s") {
        //currentTime是时间的设置(快进、后退)    
        v1.currentTime += 5;
    } else if (event.target.value == "后退5s") {
        v1.currentTime -= 5;

    } else if (event.target.value == "0.2倍播放") {
        // playbackRate是倍数播放(0.1-16 —— 1是普通速度,小于1是慢放,大于1是快放)
        v1.playbackRate = 0.2;
    } else if (event.target.value == "1.5倍播放") {
        v1.playbackRate = 1.5;
    } else if (event.target.value == "1倍播放") {
        v1.playbackRate = 1.5;

    } else if (event.target.value == "全屏") {
        // 全屏
        launchFullscreen(v1);
        // v1.webkitRequestFullscreen();谷歌浏览器全屏
    }
})



//解决浏览器兼容性
function launchFullscreen(element) {
    if (element.requestFullscreen) {
        element.requestFullscreen();
    } else if (element.mozRequestFullScreen) {
        element.mozRequestFullScreen();
    } else if (element.webkitRequestFullscreen) {
        element.webkitRequestFullscreen();
    } else if (element.msRequestFullscreen) {
        element.msRequestFullscreen();
    }
}

拖拽:

// 源对象
let divEle = document.getElementsByClassName("sou")[0];

// 获取鼠标在源对象中的位置
let sX, sY;

divEle.addEventListener("dragstart", function (e) {
    let event = e || window.event;
    // console.log("dragstart");
    // 获取当前鼠标在节点的位置
    sX = event.offsetX;
    sY = event.offsetY;
})

divEle.addEventListener("drag", function (e) {
    console.log("drag");
})

divEle.addEventListener("dragend", function (e) {
    console.log("dragend");
})


// 目标对象
let divEle1 = document.getElementsByClassName("tou")[0];
// 监听鼠标是否移入
divEle1.addEventListener("dragenter", function () {
    console.log("dragenter");
})

// 监听源目标是否在目标对象之上(一直触发)
divEle1.addEventListener("dragover", function (e) {
    let event = e || window.event;
    event.preventDefault();
})


// 监听鼠标是否移出
divEle1.addEventListener("dragleave", function (e) {
    console.log("dragleave");
})

// 监听鼠标是否移出(是否触发,dragover中是否阻止默认事件)
divEle1.addEventListener("drop", function (e) {
    let event = e || window.event;
    let taX = this.offsetLeft;
    let taY = this.offsetTop;
    divEle.style.left = `${event.clientX-sX-taX }`+"px";
    divEle.style.top = `${event.clientY-sX-taY}`+"px";
    this.appendChild(divEle);
})

本地存储:

cookie:只能存储在当前页面,每次存储的数据不能大于4kb
session(会话)

sessionStorage存储:
sessionStorage中存储的键值对都是以string类型存储的
缺点:如果更换了根目录,则存储的数据消失

// 设置数据(增添、修改)
sessionStorage.setItem("className", "f70");

// 获取数据
let cn = sessionStorage.getItem("className");
// console.log(cn); //f70

// 删除数据
sessionStorage.removeItem("className");
cn = sessionStorage.getItem("className");
// console.log(cn); //null

//清空sessionStorage里的数据
sessionStorage.setItem("username", "f71");
sessionStorage.setItem("pwd", 123);
sessionStorage.setItem("balance", 1000);
sessionStorage.clear();

let obj = {
    name: "abc",
    age: 18,
    say() {
        console.log("hello");
    }
}
// JSON.stringify()把JS中各类型数据转换成"字符串"进行存储。
sessionStorage.setItem("obj", JSON.stringify(obj));
console.log(typeof sessionStorage.getItem("obj")); //string

// 把sessionStorage获取到的值,转换成原本的数据类型
let info = sessionStorage.getItem("obj");
obj = JSON.parse(info);
console.log(typeof obj,obj);//object,{age:18,name:"abc"}

localStorage 永久存储
sessionStorage的方法均可使用

sessionStorage与localStorage的区别:
sessionStorage如果在使用当前页面的值,更改值后,而第二个相同地址中页面的值不会更改;
当关闭页面后,存储的值都会消失。
localStorage如果在使用当前页面的值,更改值后,而第二个相同地址中页面的值会更改;
当关闭页面后,同一个地址下,存储的值不会消失。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值