前端-javascript--JavaScript语法

1、JavaScript的组成

JavaScript由ECMAScript(JavaScript语法)、DOM(文档对象模型)、BOM(浏览器对象模型)

2、输入输出语句

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        //1.alert()弹框
        alert("这是弹出框提示文本")

        //2.confirm()返回true或false
        var x;
        var r = confirm("请按下按钮!");
        if (r == true) {
            x = "你按下的是\"确定\"按钮。";
        } else {
            x = "你按下的是\"取消\"按钮。";
        }
        document.write(x)


        //3.prompt() 返回第二个参数内容
        var x;
        var name = prompt("请输入你的名字", "Keafmd"); //显示默认文本 "Keafmd"
        if (name != null && name != "") {
            x = "你好! " + name + "。";
            document.write(x)
        }
       //4.console.log()后台打印
    </script>

</head>

<body>

    <p>alert是阻塞的函数</p>
    <p>这句话只有在确认弹出框的提示文本后才会显示</p>
</body>

3、变量

3.1 变量命名

  • 由字母(A-Z,a-z),数字(0-9),下划线(_),美元符号($)组成,如:usrAge,num01,__name
  • 不能以数字开头,不能用关键字命名,区分大小写,如Var与var不同

3.2 变量提升

再预编译阶段会进行变量提升,即定义提取到最前面。

var关键字变量提升,初始值为undefined

function会变量提升,初始值为函数定义值

  1. 优点:解析和预编译过程中的声明提升可以提高性能,让函数可以在执行时预先为变量分配栈空间;声明提升还可以提高JS代码的容错性,使一些不规范的代码也可以正常执行。
  2. 缺点:变量提升导致的问题:变量被覆盖,变量没有被销毁

3.3 let const var的区别

  1. 区别:let 和const 定义的变量不能变量提升,var可以变量提升。尝试在声明前去使用 let 和 const这两个关键字声明的变量,就会报错,形成暂时性死区。
  2. let 和const不能重复声明。var可以重复声明。
  3. const定义时就要初始化,let 和const不用。

3.4 变量提升考题

具体参考:JavaScript之预编译与变量提升、window、AO、GO、return、if_aoif_牧码侠的博客-CSDN博客

补充习题理解

//会报错fn is not a function,关键字变量提升fn,但是没有赋值,其值为Undefined,没有指向函数地址
//执行顺序是var fn=undefined  fn()  fn=function(){}
fn()
var fn=function(){}


//函数变量提升,知道了函数的名字与其地址,执行顺序是function fn2(){}   fn2()
fn2()
function fn2(){}
1、
var a = 1;
function b(){
    a = 10;  //覆盖了内部的函数对象,函数内部变量按照作用域链进行查找
    return;
    function a(){
        console.log(a);
    }    
}
b();
console.log(a); //1

var name1 = "Tom";
function aa() {
  // var name1 = "Jack";
  name1 = "Jack";
  console.log(name1);  //jack
}
aa();
console.log(name1);   
//函数内部var name1 = "Jack";结果时“Tom”,函数里面前后修改name1不影响外部
//函数内部 name1 = "Jack";结果时"Jack"
// 因为预编译不管是否会进入判断
// 都会发生变量提升

2、
var a = 1;
function b(){
    a = 10;   
}
b();
console.log(a); //10

3、
function a(a) {
  var a;
  console.log( a);  // 1  先变量提升,然后形参赋值,再函数赋值,再执行代码
}
a(1);

function a(a) {
  var a = 2;
  console.log("EE", a); //2
}
a(1);

function a(a) {
  console.log("EE", a); //函数,作用域链???
  function a() {
    var b = 5;
    console.log(b);
  }

}
a(1);

3、
立即执行函数不可以调用,也不会进行变量提升
var name1 = "Tom";
//aa is not defined
console.log(aa);
(function aa() {
  console.log(name1, typeof name1);
  var name1 = "Jack"; //存在时,name==undefined,不存在时name="Tom"
})();
//aa is not defined
console.log(aa);

拓展:结合原型链

new new Foo().getName();笔试考题;优先级等问题_new foo().print-CSDN博客

凡科前端笔试之打印题_前端打印什么的题目-CSDN博客

//写出以下输出结果
function Foo() {
    getName = function () { alert (1); };
    return this;
}
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
var getName = function () { alert (4);};
function getName() { alert (5);}
 //请写出以下输出结果:
Foo.getName();                        // 2
getName();                            // 4调用匿名函数
Foo().getName();                      // 1 修改getName函数
getName();                            // 1
new Foo.getName();                    // 2  new( Foo.getName())
new Foo().getName();                  // 3  ( new Foo()).getName()
new new Foo().getName();              // 3

4、数据类型

JS 把数据类型分为两类:

基本数据类型(Undefined,Null,symbol,bigint,Number,String,Boolean,),存在栈中。

复杂数据类型(Object, Array,function,Math,Date,RegExp),存在堆中,地址交给存在栈中的变量名管理

补充:其中基础数据类型的 boolean、number、string又称为包装类型

valueOf() 是 Object 的原型方法,它定义在 Object.prototype 对象上,所有 Object 的实例对象都会继承 valueOf() 方法。???

对数据的操作是灵魂哟,所以有需要的,就根据自己情况做笔记,哈哈哈

5、Undefined与Null

typeOf null   //Object
null instanceof Object  //false
null === undefined  //false
null == undefined    //TRUE
NaN == NaN  //false
isNAN(Number(NAN))  //TRUE

alert(0 == ''); //true
alert(0 == false); //true
alert(false == ''); //true
alert(null == undefined); //true

alert(!0); //true
alert(!false); //true
alert(!undefined); //true
alert(!null); //true
alert(!''); //true

alert(0 == undefined); //false
alert(0 == null); //false
alert(false == null); //false
alert(false == undefined);//false
alert('' == null); //false
alert('' == undefined); //false

console.log(10+null,10+"",10+undefined,10+false,"10"+0)
//10 10 NaN 10 100

console.log(10+["1","a"],10+[1,"a"],10+[1,2],10+[1,"2"])
//101,a 101,a 101,2 101,2

console.log(parseInt(["1q","2"])) //1

console.log([]==0,[]==false,[]==undefined)  //true,true,flase
console.log(![]=="",[]=="",![],!"",[])  //true true false true [] 
console.log(!{}=="",{}==false,1+{})  //true false 1[object Object]

5、Symbol

Symbol()生成唯一值相同参数生成两个Symbol值不相等

Symbol.for() 用于将描述相同的Symbol变量指向同一个Symbol

Symbol.keyFor()是用来检测该字符串参数作为名称的 Symbol 值是否已被登记,返回一个已登记的 Symbol 类型值的 key

const s3 = Symbol('debug');
const s4 = Symbol('debug');
console.log(s3 === s4); // false

let a1 = Symbol.for('a');
let a2 = Symbol.for('a');
a1 === a2  // true

let a3 = Symbol.for("b");
Symbol.keyFor(a3);    // "a"

let a4 = Symbol("c");
Symbol.keyFor(a4);    // undefined

6、Number

参考:JavaScript面试大师_Number类型_js面试 number-CSDN博客

6.1、为什么0.1 + 0.2 = 0.30000000000000004?

0.1和0.2是十进制小数,对应分数是1/10和1/5,将它们用二进制表示均是循环小数,基于IEEE 754格式二进制表示循环小数实际上是截断后的近似值,相加后的值比十进制的0.3略大。可以使用toFixed()解决,或者规定允许误差

toFixed(2)保留两位小数,四舍五入由误差

6.2、给Number加一个方法newRound,可以保留小数点后n位 (1.23457.newRound(2) -> 1.23)

6.3、Number(undefined) ,Number(null)  typeof NaN 

NaN  0 number

6.4、Number()函数的转换规则

Object转换为Number的规则如下:

对于复杂类型:会先调用该值得valueOf()方法,如果有并且返回基本类型之,就是用该值进行强制类型转换。如果没有就是使用toString()的返回来进行强制类型转换。

Number([])和Number([1,2,3])的值分别是什么?说明其原理?

因为数组的valueOf()方法返回的是数组本身,不是一个基本类型,所以还会调用toString()方法;而数组的toString()方法返回的是数组各项通过逗号拼接一起的字符串(可以理解调用了Array.prototype.join(",")方法),所以空数组返回空字符串,转换为数组自然就是0;而数组[1,2,3]则是“1,2,3”再转换为NaN

Number([100])  //100

6.5、["1", "2", "3"].map(parseInt) 答案是多少?

解答:[1, NaN, NaN] ,首先需要明确arr.map(function(item, index, arr){})以及parseInt(numStr, radix),迭代数组元素的过程中,传给parseInt函数的第一个参数是item,第二个是index,因此返回结果为[parseInt("1", 0), parseInt("2", 1), parseInt("3", 2)],parseInt的第二个参数是进制基数,后两个元素解析错误,返回NaN

6.6、parseInt(string,radix)

parseInt(stringradix) 以radix进制解析字符串,不会四舍五入

parseInt('ff', 16)  //15*16^1+15*16^0=255

6.7、isNaN()与Nnuber.isNaN()

isNaN():输入参数是否可以转化为数字,即先进行Number转换,再判断

Nnuber.isNaN():先判断输入参数的类型是否为number,再调用isNaN方法

isNaN("11")  //true

isNaN("11a")  //false

6.8、字符串 + 任何类型 = 拼接之后的新字符串

alert('100' + '100'); // 100100

console.log(11 + undefined); // NaN

console.log(true + undefined);// NaN

console.log("你好" + undefined); // 你好undefined

6.9、运算符优先级

三元表达式

//如果表达式1为 true ,则返回表达式2的值,如果表达式1为 false,则返回表达式3的值

表达式1 ? 表达式2 : 表达式3;

6.10、短路运算(逻辑中断)

alert(0&&'a'); 结是返回 0

  • 1、只要 || 前面为 false,无论 || 后面是true还是 false,结果都返回 || 后面的值。
  • 2、只要 || 前面为 true,无论 || 后面是true还是 false,结果都返回 || 前面的值。
  • 3、只要 && 前面是 false,无论 && 后面是true还是 false,结果都将返 && 前面的值;
  • 4、只要 && 前面是 true,无论 && 后面是true还是false,结果都将返 && 后面的值;
  • 5、“”==false==0是一样的;null==undefined

7、String

参考JavaScript 28个常用字符串方法及使用技巧 - 掘金 (juejin.cn)

7.1、字符串方法,你懂多少?

我薄弱点:

7.1.1、charCodeAt():该方法会返回指定索引位置字符的 Unicode 值

let str = "abcdefg";

console.log(str.charCodeAt(1)); // "b" --> 98

拓展:

1、对应十进制的unicode编码

“a”--97   "A"---65  "1"--48

2、将元素转化为unicode编码

toString(16)方法  

10.toString(2) //"1010"将数字转化为2进制的字母

将字符串转化为unicode编码:str.charCodeAt(i).toString(16);

3、encodeURI(URIstring):encodeURI() 函数可把字符串作为 URI 进行编码。

decodeURI(URIstring):decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码。

7.1.2、string.split(separator,limit)

separator:必需。字符串或正则表达式,limit:可选。该参数可指定返回的数组的最大长度。

const fruits = list.split(/[,;]/,4)

7.1.3、slice(start,end) , substring(start,end)

返回的子串包括开始处的字符,但不包括结束处的字符

区别于string.substr(start,length)

7.1.4、repeat(n)

表示将原字符串重复n次,如果参数是小数,会向下取整。如果参数是小于-1的负数或者Infinity,会报错。参数是 0 到-1 之间的小数或NaN,则等同于 0,返回空字符串

7.1.5、string.match(regexp)返回存放匹配结果的数组

let str = "abcdef";

console.log(str.match("c")) // ["c", index: 2, input: "abcdef", groups: undefined]

笔试题

var str = "2[2[ab7[d]]3[c]]4[e]";
const decode = (str) => {
  if (!/\d+\[[a-zA-Z]+\]/g.test(str)) return str;
  // var test = str;
  // console.log(test.replace(/\d+\[[a-zA-Z]+\]/g, "啊"));
  str = str.replace(/\d+\[[a-zA-Z]+\]/g, function (item, index) {
    //item是指7[d] 3[c] 4[e],index时item的起始下标
    // console.log("测试", index, item);
    // 匹配符合规制的字符串
    // var arrtest = item.match(/\d+\[[a-zA-Z]+\]/);
    // console.log("arrtest", arrtest);
    // 匹配符合规制的字符串并保留括号里面的内容
    // var arr = item.match(/(\d+)\[([a-zA-Z]+)\]/);
    // console.log("arr", arr);

    var arr = item.match(/(\d+)\[(.+?)\]/).slice(1);
    var s = arr[1].repeat(arr[0]);
    return s;
  });
  // console.log("str", str);
  str = decode(str);
  return str;
};
decode(str);

var matchStr = "{a}2{b{{c}d}2}3";
const matchCode = (matchStr) => {
  if (!/\{[a-zA-Z]+\}\d*/g.test(matchStr)) return matchStr;
  matchStr = matchStr.replace(/\{[a-zA-Z]+\}\d*/g, function (item, index) {
    console.log(item, index);
    var flagarr = item.match(/\{([a-zA-Z]+)\}(\d*)/).slice(1);
    var s2 = flagarr[1] == "" ? flagarr[0] : flagarr[0].repeat(flagarr[1]);
    console.log("s2", s2);
    return s2;
    // console.log("flagarr", flagarr);
  });
  matchStr = matchCode(matchStr);
  console.log("matchStr", matchStr);
  return matchStr;
};
matchCode(matchStr);

7.1.6、string.search(searchvalue)返回相匹配的子串的起始位置。

let str = "abcdef"; str.search(/bcd/) // 输出结果:1

7.1.7.parseInt(string, radix) 返回将string转化为radix进制的数字

7.1.8、JSON.stringify将一个JavaScript对象或值转换为JSON格式字符串。

参考:JSON.parse 和 JSON.stringify 详解 - 掘金 (juejin.cn)

JSON.stringify(value[, replacer [, space]])

  • value:将要序列化成 一个JSON字符串的JavaScript对象或值。
  • replacer 可选,用于处理将要序列化的值。
  • space 可选,指定缩进用的空白字符串,用于美化输出。
  1. 基本类型值字符串、数字、布尔值,以及String、Boolean、Number对象值,都会转成原始值字符串输出。基本类型的字符串,转换结果会带双引号。 因为在还原时,双引号会让JavaScript知道是字符串,而不是变量。
  2. undefined、函数、symbol以及XML对象:
  • 出现在Object对象中时,会被忽略;
  • 出现在数组中时,会被序列化成null;
  • 单独出现时,会返回undefined。

        3.NaN、null,都会被序列化成null。

        4.replacer参数,如果是一个数组,则只有包含在这个数组中的属性名,才会最终被序列化到结果字符串中。只对对象的属性有效,对数组无效。如果是一个函数,被序列化的值的每个属性都会经过该函数的转换和处理。

JSON.stringify(333) // '333'
JSON.stringify(true) // 'true'
JSON.stringify(new String('333')) //'"333"'
JSON.stringify(Boolean(true)) // 'true'
JSON.stringify(Symbol()) // undefined
JSON.stringify([Symbol(), Math.abs, undefined]) // '[null,null,null]'
JSON.stringify({ [Symbol()]: Math.abs, key: undefined }) // '{}'

const obj = {
  json: 'JSON',
  parse: 'PARSE',
  stringify: 'STRINGIFY'
}
JSON.stringify(obj, ['parse', 'stringify'])
// '{"parse":"PARSE","stringify":"STRINGIFY"}'

JSON.stringify({ json: 1, stringify: 'rr' }, (key, value) => {
  if (typeof value === 'number') {
    return 'ss'
  }
  return value
}) 
// '{"json":"ss","stringify":"rr"}'

7.1.9、JSON.parse(text[, reviver])将json字符串转成json对象(js对象值)

该方法也支持数字、布尔值和null三个类型的值,转换出对应的字面值,不支持数组,不能使用undefined、Symbol和BigInt。,数字也不支持NaN、Infinity和-Infinity,

JSON.parse(null) // null
JSON.parse(111.) // 111
JSON.parse('{"key": 1 }') //{"key": 1 }
JSON.parse('[]') //[]

 补充:AJAX和JSON的区别

  • ajax是一种通过后台与服务器进行少量的数据交换的异步JavaScript和xml,使页面实现异步更新。
  •  json是一种轻量级的数据交换格式,看着像对象,本质是字符串

ajax的优缺点

  1. 优点:可以实现异步通信效果,页面局部刷新,带来更好的用户体验。按需取数据,减少了冗余请求和服务器的负担;
  2. 缺点:异步回调问题、this指向问题、路由跳转back问题;对搜索引擎的支持比较弱,对于一些手机还不是很好的支持

json的优缺点

  1.  优点:轻量级(格式都是压缩的,占用宽带小)、易于人的阅读和编写,便于js解析(难度较低比起XML简单的多),支持复合数据类型,支持多种语言
  2. 缺点 :没有XML格式这么推广的深入人心和使用广泛, 没有XML那么通用性

8、数组

8.1、常用数组的方法,你懂多少?

8.1.1、改变原数组的方法

pop(),shift(),unshift(),push(),sort((a,b)=>a-b),splice(start,num,element),reverse(),fill()

8.1.2、高阶函数的数组方法

forEach,map,some,every,find,filter,sort,reduce

8.1.3、普通数组方法

concat,includes,indexOf,join

8.2、考点(我的薄弱点)

8.2.1、Array.from(iterable, mapFn, thisArg)

将字符串活对象或字典转化为数组,或者拷贝数组

//使用类似数组的对象创建数组
const obj = {
  0: "榴莲",
  1: "牛油果",
  2: "蓝莓",
  length: 3
};
console.log( Array.from(obj));  //[ '榴莲', '牛油果', '蓝莓' ]

//使用映射函数处理数组元素
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = Array.from(numbers, num => num * 2);
console.log(doubledNumbers); //[ 2, 4, 6, 8, 10 ]

8.2.2、创建二维数组

let a=Array(5).fill(null) // -> [null, null, null, null, null]

8.2.3 将多维数组转化为一位数组

function flatten(arr) {
  return [].concat(...arr.map((x) => (Array.isArray(x) ? flatten(x) : x)));
}
let arr = [[1, 2], 3, [[[4], 5]], 1];
var res = arr.reduce((pre, cur) => {
  if (Array.isArray(cur)) {
    cur = flatten(cur);
  }
  return pre.concat(cur);
}, []);

const arr4 = [1, [1, 2], [1, [3]]];
arr4.flat(Infinity)

8.2.4 一维数组去重

let set=new Set(arr)

let arr=[...set]

8.2.5 二维数组去重

function removeDuplicate(arr) {
  let obj = {}
  arr.map(item => {
    if (!obj[item]) {
      obj[item] = true
    }
  })
  return Object.keys(obj)
}
const arr = [[1, 1], [2, 2], [1, 1]];

// 使用ES6 Set()去重
const deduplicatedArr = Array.from(new Set(arr.map(JSON.stringify))).map(JSON.parse);

9、对象

9.1、创建对象的三种方式

  • 利用字面量创建对象
  • 利用 new Object创建对象
  • 利用构造函数创建对象
//构造函数形式
function 构造函数名(形参1,形参2,形参3) {
 this.属性名1 = 参数1; 
this.属性名2 = 参数2;
 this.属性名3 = 参数3;
 this.方法名 = 函数体; 
}
var obj = new 构造函数名(实参1,实参2,实参3)

9.2 、继承

class Father {
     constructor(surname) {
                this.surname = surname;
            }
    say() {
        return '我是爸爸';
    }
}
class Son extends Father {
     constructor(surname, firstname) {
                super(surname); //调用父类的 constructor(surname)
                }
    say(){
        // super.say() super调用父类的方法
        return super.say() + '的儿子';
    }
}

var damao = new Son();
console.log(damao.say());

9.3、new 实现

  1. 首先创一个新的空对象。
  2. 根据原型链,设置空对象的 __proto__ 为构造函数的 prototype 。
  3. 构造函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)。
  4. 判断函数的返回值类型,如果是引用类型,就返回这个引用类型的对象。

9.4、原型链

区分:对象的原型(proto),构造函数的原型对象(prototype)

  1. js分为函数对象和普通对象,每个对象都有__proto__属性,但是只有函数对象才有prototype属性
  2. 原型:每一个 JavaScript 对象(null 除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性,其实就是 prototype 对象。

访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链

继承的时候只需要把子类的原型对象prototype里的__proto__属性指向父类的prototype即可

9.5、bind、call和apply的区别

  • apply 、 call 和 bind 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。
  • apply 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。
  • call 方法接收的参数,第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。也就是说,传递给函数的参数必须逐个列举出来。
  • bind 方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。(不会调用函数,需要赋值之后再调用)这个函数的 this 指向除了使用 new 时会被改变,其他情况下都不会改变。
let arr=[1,2,3]
Math.max.call(null,...arr])
Math.max.apply(null,arr])
Math.max.bind(null,arr])()

后续补充:手撕apply 、 call 和 bind????

9.6、对象的方法与遍历对象

// 作用: 用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
Object.assign()
// 作用 : 创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
Object.create()
// 作用 : 返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致
Object.entries()
// 作用 : 会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
Object.keys()
// 作用 : 返回一个给定对象自身的所有可枚举属性值的数组,
Object.values()
// 作用: 判断两个值是否为同一个值
Object.is() 
// 作用 : 直接在一个对象上定义新的属性或修改现有属性
Object.defineProperty()
// 用来检测obj是否含有特定的自身属性name。
obj.hasOwnProperty('name')

//遍历
for(let key in obj){
    console.log(key, obj[key])
}
Object.keys(obj).forEach(key=> console.log(key, obj[key]))

9.7、对象的合并方法、深克隆

function mergeObject(...objs) {
    let result = {}
    objs.forEach(obj => {
        Object.keys(obj).forEach(key => {
            let value = obj[key]
            if (!result.hasOwnProperty(key)) { // 说明result中没有该属性
                result[key] = value
            } else { // 说明result已经存在该属性,那么就把同名属性的值合并为一个数组
                result[key] = [].concat(result[key], value)
            }
        })
    });

    return result
}
function deepClone(obj = {}) {    // 判断传入的 obj 是不是数组或对象,不是直接返回 obj    
if (typeof obj !== 'object' || obj == null) {       
return obj;            
}    
let result;    // 判断是不是数组    
if (obj instanceof Array) {        
    result = [];    
    } else {        
    result = {};    
    }    
    for (let key in obj) {        // hasOwnProperty()方法:检测一个属性是否是对象的自有属性        
    if (obj.hasOwnProperty(key)) {            // 递归调用            
    result[key] = deepClone(obj[key]);        
    }    
}    
return result;}

10、函数

10.1、函数类型

命名函数 function 函数名(){}

匿名函数 var 变量名= function (){}

立即调用函数(function (){})()

10.2 、作用域链

根据[内部函数可以访问外部函数变量] 的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链。

10.3、闭包机制

什么是闭包

函数内部的变量函数外部无法访问,这形成了闭;函数外部想得到函数内部的变量,可以通过某些方法譬如通过return等语句将内部的变量暴露出去,这形成了包

即闭包是有权限访问其他函数作用域的局部变量的一个函数

闭包的作用

将函数内部的私有变量保存了下来(不被修改),并且拓展了变量的使用范围

闭包应用

参考:JavaScript | 图解 | 闭包应用之循环事件绑定的N种解决办法 - 掘金 (juejin.cn)

(1)为节点循环绑定click事件

将var改为let,通过let形成闭包

(2)回调函数:柯里化

(3)防抖与节流:通过闭包可以实现传参效果

防抖:在一定时间间隔内将多次触发变成一次触发,减少函数执行次数

  • 持续触发不执行
  • 不触发的一段时间之后再执行

运用场景:

  • 搜索框搜索输入,只需要用户最后一次输入完再发送请求。
  • 窗口大小resize,只需窗口调整完成后,计算窗口大小。防止重复渲染。

节流:当触发事件后,每隔一固定时间,就执行一次。但是在固定时间内,多次触发,却只执行一次函数。

  • 持续触发并不会执行多次
  • 到一定时间 / 其它间隔 ( 如滑动的高度 )再去执行

作用:都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。

应用场景:

  • 滚动加载,加载更多或滚到底部监听。
  • 搜索框,搜索联想功能。
//防抖
let timer = null
    function debounce(fn, delay) { // fn: 需要防抖的函数,delay:延迟的时间
        timer&&clearTimeout(timer)
        timer = setTimeout(fn, delay)
    }
写法2:
function debounce(fn, delay) {
    let timer;
    return function() {
        let context = this;
        let args = arguments;
        timer && clearTimeout(timer);
        timer = setTimeout(function() {
            fn.apply(context, args);
        }, delay);
    };
}

//节流
// 前缘节流,首次触发立即生效,后续需要间隔一段时间触发才生效
function throttleImmediateExecution(fn, delay){
    let timer = null; // 使用定时器实现
    return function (){
       let _this = this; // 当前 this 保存,以免后续处理中 this 丢失
        if(!timer){
               fn.apply(_this, arguments);
               timer = setTimeout(function (){
                timer = null;           
                }, delay);        
                }    
            }}


export default function throttle(fn,interval){
    //last 为上一次触发回调的时间
    let last = Date.now()
    return function(){
        // 保留调用时的this上下文
        let context =this
        // 保留调用时传入的参数
        let args = arguments
        // 记录本次触发回调的时间
        let now = Date.now()
        // 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
        if(now-last>=interval){
            last =now;
            fn.apply(context,args)
        }
    }
}

闭包能够造成内存泄漏

页面不关闭,变量就一直在,不能被垃圾回收机制回收或者手动清除。

函数参数

函数体内不用定义直接调用arguments,它是一个伪数组,没有数组的方法,拥有数组的属性,即下标索引与length

11、内置对象-Math对象

属性、方法名

功能

Math.PI

圆周率

Math.floor()

向下取整

Math.ceil()

向上取整

Math.round()

四舍五入版 就近取整   注意 -3.5   结果是  -3

Math.abs()

绝对值

Math.max()/Math.min()

求最大和最小值

Math.random()

获取范围在[0,1)内的随机值,包括第一个数,不包括第二个数

1. Math.floor向下取整
Math.floor(5.95)  //5
Math.floor(-45.95); // -46
2. Math.ceil向上取整
Math.ceil(7.004)  //8
Math.ceil(-7.004)  //-7
3. Math.round 返回一个数字四舍五入后最接近的整数。
x = Math.round(20.49); //20
x = Math.round(20.5); //21
x = Math.round(-20.5); //-20

4.Math.random() 函数返回一个浮点数,伪随机数在范围从0 到小于1

Math.power(a,n)
Math.sqrt(a)

12、Date日期对象

  //日期格式化
        // 格式化日期 年 月 日
      var date = new Date();
      console.log(date.getFullYear()); //返回当前日期的年 2020
      console.log(date.getMonth() + 1); //月份 返回的月份小1个月,记得月份加1呦
      console.log(date.getDate()); //返回的是 几号
      console.log(date.getDay); //周一返回的是1 周六返回的是6 周日返回的是0
      //我们写一个 2020年 9月 6日 星期日
      var year = date.getFullYear();
      var month = date.getMonth() + 1;
      var dates = date.getDate();
      var day = date.getDay();
      if (day == 0) {
        day = "星期日";
      }
      console.log("今天是" + year + "年" + month + "月" + dates + "日" + day);

var now = Date.now(); //当前的时刻

12、RegExp()正则匹配

str="abc"

let reg=new RegExp("[a]b",gi)                reg.test(str)

let res=/[a]b/.test(str)

需要回顾match replace search

13、类型检测

13.1、 typeof  检查基本类型

除了数组,对象,null是Object外,其他都是正常

typeof(null)  //Object

13.2、instanceof 检查引用类型

 其原型链上是否存在其构造函数。

let car = new Car();

let arr = [];

let fun = () => {};
let num = 1;

console.log(car instanceof Car);  //true

console.log(arr instanceof Array);  //true

console.log(fun instanceof Function);  //true

console.log(num instanceof Number);  //false

13.3、constructor检查所有类型

function Person(name) { this.name = name; }

Person.prototype.constructor === Person // true

 13.4、Object.prototype.toString.call(obj)检查所有类型

console.log(Object.prototype.toString.call("jerry"));//[object String]
console.log(Object.prototype.toString.call(12));//[object Number]
console.log(Object.prototype.toString.call(true));//[object Boolean]
console.log(Object.prototype.toString.call(undefined));//[object Undefined]
console.log(Object.prototype.toString.call(null));//[object Null]
console.log(Object.prototype.toString.call({name: "jerry"}));//[object Object]
console.log(Object.prototype.toString.call(function(){}));//[object Function]
console.log(Object.prototype.toString.call([]));//[object Array]
console.log(Object.prototype.toString.call(new Date));//[object Date]
console.log(Object.prototype.toString.call(/\d/));//[object RegExp]

function Person(){};
console.log(Object.prototype.toString.call(new Person));//[object Object]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值