声明变量
关键字
ES5 var 全局作用域下的 (window) var 声明变量
ES6 let const 块级作用域 只有块级作用域的概念
let 声明的变量只在let命令行内存在的代码块中有效
const 声明一个只读的常量 一旦声明就不能改 而且必须要初始化(赋值)
区别:
1.语法的区别
2.作用域不同
3.const 只读的常量
4.重复声明变量?
5.暂时性死区
6.变量提升是否初始化?
操作符
==(不严格的等于)!=(不严格的不等于) ===(严格的等于)!==(严格的不等于)
1.=== :称为等同符,先类型是否相等 如果相等 再判断值是否相等
2.==:称为等值符,当等号两边的类型相同时,直接比较值是否相等,若不相等 先转换类型 在比较值
!取非 取反
数据类型
在ES5的时候 ,我们认知的数据类型确实是有 6种:Number String Boolean undefinrd Object Null
ES6中 新增了一种Symbol。永不相等 独一无二。
谷歌6,7版本 中 bigInt (大整数) (个人觉得不是)
js数据类型:js数据类型有几种
7种:Number String Boolean undefinrd Object Null Symbol
typeof 用判断数据类型的 返回值 Number String Boolean undefinrd Object Symbol function
instanceof 用于判断对象是谁的实例
hasOwnProperty() 判断某个属性是否存在于某个对象中 in 运算符配合完成
isPrototypeOf() 检测一个对象是否是另一个对象的原型
循环结构
while 循环
while(条件) 语句;
//举栗子
var i = 0
while(i<10){
console.log(i);
i=i+1;
}
do while
先循环 后判断 最少要执行一次循环体
do 语句 while(条件)
//举栗子
var x = 3;
var i =0
do{
console.log(i);
i++;
}while(i<x)
for循环
for (基数器; 循环条件; 累次循环) { 循环体 }
扩充:
js性能优化之for循环
1.最常规的写法
for(var i = 0;i<10;i++){
//do something
}
2.循环次数为变量的情况
for(var i = 0;i<arr.length;i++){
//do something
}
3.变量情况的优化
for(var i = 0,l = arr.length;i<l;i++){
//do something
}
4.也可以这样写
var i = 0;
var l = arr.length;
for(;i<l;i++){
//do something
}
5.优化版本的升级版
for(var i = arr.length - 1;i>=0;i--){
//do something
}
for...in循环
主要运用于对象
var obj = { a: 1, b: 2, c: 3 }
for (const key in obj) {
console.log("键名",key);
console.log("键值",obj[key]);
}
for (const key in object) {
if (object.hasOwnProperty(key)) {
const element = object[key];
}
}
for..of
数组
var arr = [1,2,3,4,5,1]
for (const key of arr) {
console.log(key);
}
set map
var s = new Set([1,2,3,4,5,6])
for (const key of s) {
console.log(key);
}
var m = new Map()
m.set('a',1)
m.set("b",2)
for (var [key,value] of m) {
console.log(key +":"+value);
}
nodeList 字符串 arguments
// 字符串
var str = "hello";
for (let s of str) {
console.log(s); // h e l l o
}
// DOM NodeList对象
let paras = document.querySelectorAll("p");
for (let p of paras) {
p.classList.add("test");
}
// arguments对象
function printArgs() {
for (let x of arguments) {
console.log(x);
}
}
printArgs('a', 'b');// 'a' 'b'
数组
函数
普通函数
function fn() {
console.log(123);
}
fn()//有名函数
//通过自变量创建的函数
var fn =function(){console.log(123);}
//匿名函数
(function(){console.log(123);}())
//通过构造函数
var fn = new Function('console.log(123);')
构造函数
function Person(name,age,company) {
this.name = name;
this.age = age;
this.company = company;
this.sayName = function () {
console.log(this.name);
}
}
var yunmu =new Person('云牧',18,"潭州教育")
var deft = new Person('deft',18,'潭州教育')
var leap = new Person('leap',18,"潭州教育")
var qinqi = new Person('倾奇',18,'潭州教育')
console.log(yunmu);
console.log(deft);
console.log(leap);
console.log(qinqi);
每次new实例的时候会把构造函数中的方法也实例了 对内存有损耗 节省内存 原型模式
但是如果原型模式中出现参数是引用类型 如果去改变值通过P1 的话 会直接改变原型上的值 导致所拿到是数据不是所想要的 提出了组合模式
寄生构造函数模式 除了用new操作符并把使用的包装函数叫做构造函数之外 几乎和工厂模式一模一样
稳妥模式
引申工厂模式 工厂模式和构造函数模式 区别:
对比工厂模式的不同之处有:
1.没有显式创造对象
2.直接将属性和方法赋给了this
3.没有return语句
构造函数和普通函数的区别:
1.构造函数其实也是一个普通函数 普通函数和构造函数首字母不同 普通函数小写 构造函数大写
2.构造函数用创建了一个新的实例对象
3.调用方式不一样 构造函数new 普通函数之间通过函数名调用
4.构造函数内部是用this来构造方法和属性
5.普通函数返回没有值 所以undefined ;构造函数 会返回一个新的对象
6.instanceof可以检查一个对象是否是一个类的实例
8.构造函数的执行流程 A.立刻在堆内存中创建一个新的对象 B.将新建的对象设置为函数中的this C. 逐个执行函数中的代码 D.将新建的对象作为返回值
普通函数和箭头函数的区别
1.外形不同
2.箭头函数 匿名函数
3.箭头函数是不可以作为构造函数的
4.箭头函数中this指向不同
5.箭头函数中不具备arguments对象的
6.其他
6.1 箭头函数不能Generator函数 。
6.2 箭头函数不具备prototype原型对象。
6.3 箭头函数是不具备super
6.4 箭头函数不具备new.target(new.target该表达式在函数中使用,返回的是当前的构造函数。若该函数不是通过new调用的,则返回undefined)
对象
创建对象的几种方式
1.调用系统的构造函数创建对象 var obj = new Object();以字面量的方式创建对象。
2.工厂模式(自定义构造函数创建对象)
3.构造函数模式
4.原型模式
5.组合模式
6.动态原型模式
7.寄生构造函数模式和稳妥模式
8.Object.create()
函数高级
闭包
什么闭包 就是定义一个在函数内部的函数
特性 函数嵌套函数 内部函数可以访问到外部函数的变量 参数和变量不会被回收
闭包中的this
递归
什么是递归 函数自身调用自身
递归 递(递进)归(归来)递归有去有回
function factorial(n) {
if (n <= 1) {
return 1;
} else {
return factorial = n * factorial(n - 1);
}
}
console.log(factorial(5));
循环
var chen = 1;
function factorial(n) {
if (n<=1) {
return 1;
}
while (n) {
chen *= n;
n--;
}
return chen;
}
console.log(factorial(5));
尾递归优化那么请问优化的是什么 内存
尾调用自称尾递归
function factorial(n,total) {
if (n <= 1) {
return total;
} else {
return factorial(n-1,n*total);
}
}
console.log(factorial(5,1));
高阶函数
就是操作该函数的函数,该函数接受一个或多个函数作为参数并且返回一个新的函数
var even = function (x) {
return x % 2 === 0;
}
var odd = not(even)
function not(fn) {
return function () {
var result = fn.apply(this, arguments)
return !result;
}
}
//every()
console.log([1,1,3,5,5].every(odd));
函数柯里化 分步(分部)
function createCurry(func, args) {
var arity = func.length;
console.log("arity",arity);
var args = args || []
console.log("args",args);
return function () {
console.log("arguments",arguments);
var _args = [].slice.call(arguments);
console.log("_args",_args);
var a = [].push.apply(_args, args);
console.log("push",a);
console.log("_args.length",_args.length);
if (_args.length < arity) {
return createCurry.call(this, func, _args)
}
return func.apply(this, _args)
}
}
function check(str, reg) {
console.log("check",str, reg);
//str 是否符合reg验证
//test() 方法 用于检测一个字符串是否匹配某个模式
return reg.test(str);
}
var _check = createCurry(check)
var checkPhone = _check(/^1[34578]\d{9}$/);
// var checkEmail = _check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/);
checkPhone('123596');
// checkEmail('xxxxx@test.com');
箭头函数
箭头函数this 为父作用域的this 而不是调用时的this (函数体内的this对象 就是定义是所在的对象 而不是使用是所在的对象)
普通函数中的this指向的是调用它的 对象,如果说没有直接调用对象,会指向undefined 或window 一般指向widow 在严格模式下会只指向undefined
继承
1.原型链继承
2.借用构造函数(经典继承)
3.组合继承
4.原型式继承
5.寄生式继承
6.寄生组合式继承
ES6继承
class People{
constructor(name = "我是你爸",age = 100){
this.name = name;
this.age = age;
}
eat(){
console.log(`${this.name}今年${this.age}`);
}
}
class Son extends People{
constructor(name="生来就是儿子",age=18){
super(name,age)
}
eat(){
super.eat()
}
}
let s = new Son('儿子')
s.eat()
DOM操作事件
BOM操作事件
js浅拷贝与深拷贝的区别和实现方式
如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力
<script>
var a 1;
b = a; //浅内会开辟一个新的内存空间, 此时b和a都是相互独立的
b = 2;
console.log(a);//1
</script>
2.如果是引用数据类型, 名字存在栈内中, 值存在内存在中,但是栈内会提供一个引用的地址指向堆内存中的值
比如栈拷贝:
当b = a进行拷贝时, 其实复制的是a的引用地址, 而并非堆里面的值。
哪, 要是在内堆存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不是就达到深拷
3.实现浅拷贝的方法
(1) for...in只循环第一层
<script>
function simpleCopy(obj1){
var obj2 = Array.isArray(obj1) ? [] : {};
for(let i in obj1){
obj2(i) = obj1(i);
}
return obj2;
}
var obj1 = {
a: 1,
b: 2,
c: {
d: 3
}
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a);//1
alert(obj2.a);//3
alert(obj1.c.d);//4
alert(obj2.c.d);//4
</script>
Object.assign方法
<script>
var obj = {
a: 1,
b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a);//3
</script>
直接用=赋值
<script> let a[0,1,2,3,4], b = a; console.log(a===b); a[0]=1; console.log(a,b); </script>
用slice实现对数组的深拷贝
<script>
//当数组里面的值是基本数据类型, 比如String, Number, Boolean时,属于深拷贝
//当数组里面的值是引用数据类型, 比如Object, Array时,属于栈拷贝
var arr1 = ["1","2"."3"];
arr2[1] = arr.slice(0);
arr[1] = "9";
console.log("数组的原始值 :" + arr1);
console.log("数组的新值: " + arr2);
</script>
用concat实现对数组的深拷贝
<script>
//当数组里面的值是基本数据类型,比如String, Number, Boolean时,属于深拷贝
var arr1 = ["1","2","3"];
var arr2 = arr1.concat();
arr2[1] = "9";
console.log("数组的原始值: " + arr1);
console.log("数组的新值: " + arr2);
//当数组里面的值是引用数据类型,比如Object, Array时,属于栈拷贝
var arr1 = [(a:1),{b:2},{c:3}];
var arr2 = arr1.concat();
arr2[0].a = "9";
console.log("数组的原始值: " + arr1[0].a);//数组的原始值 : 9
console.log("数组的新值: " + arr2[0].a);//数组的新值 : 9
</script>
直接使用var newObj = .create(oldObj), 可以达到深拷贝的效果
<script>
function deepClone(initalObj,function) {
var obj = finaObj || {};
for(var i in initalObj) {
var prop = initalObj[i];
if(prop === obj) {
continue;
}
if(typeof prop === 'object'){
obj[i] = (prop.constructor === Array ? [] : Object.create(prop);
}else{
obj[i] = prop;
}
}
return obj;
}
</script>
使用扩展运算符实现深拷贝
<script>
//当value是基本数据类型,比如String, Number,Boolean时,是可以使用扩展运算符进行深拷贝的
//当value是引用类型的值,比如Object,Array, 引用类型进行深拷贝也只是拷贝了引用地址,所以属于栈拷贝
var car = {brand: "BMW",price: "380000",length: "5米"}
var car1 = {...car, price: "500000"}
console.log(car1);
console.log(car);
</script>
今天的内容到此结束