# 技术栈知识点巩固——Js
Posted 爱码代码的喵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了# 技术栈知识点巩固——Js相关的知识,希望对你有一定的参考价值。
技术栈知识点巩固——Js
Js 特点
- 弱类型语言:变量没有固定的数据类型。
var a=0;a="hellow world!"
- 解释性语言:不同与
c
、java
等语言需要先编译,有浏览器动态的解析与执行。 Js
是面向对象的语言。- 单线程:
Js
是单线程的。 - 跨平台:
Js
只依赖浏览器本身,实现跨平台。 - 垃圾自动回收:
Js
不需要主动回收内存,JS
引擎自动垃圾回收。
Js 阻止默认事件
- 使用原生
js
元素onclick
方法中返回false
- 或者
addEventListener
添加点击的监听,在方法体中是调用e.preventDefault();
<!DOCTYPE html>
<html>
<body>
<a href="https://www.baidu.com">百度</a>
<form action="https://www.baidu.com">
<input type="submit" value="提交" name="sub" id="submit">
</form>
<script>
let a = document.querySelector('a')
let input = document.getElementById('submit')
a.onclick = function (e)
return true
input.addEventListener('click', function (e)
e.preventDefault();
)
</script>
</body>
</html>
Js 基本类型
数据类型 | 说明 |
---|---|
null | 空值,表示非对象 |
undefined | 未定义的值,表示未赋值的初始化值 |
number | 数字,数学运算的值 |
string | 字符串,表示信息流 |
boolean | 布尔值,逻辑运算的值 |
object | 对象,表示复合结构的数据集 |
位运算
运算符 | 描述 | 运算规则 |
---|---|---|
& | 与 | 两个位都为1时,结果才为1 |
` | ` | ` |
^ | 异或 | 两个位相同为0,相异为1 |
~ | 取反 | 0变1,1变0 |
<< | 左移 | 各二进制位全部左移若干位,高位丢弃,低位补0 |
>> | 右移 | 各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃 |
typeof与instanceof
-
typeof
主要用来判断基础数据类型,instanceof
则是用来判断引用数据类型。 -
typeof
是根据数据在存储单元中的类型标签来判断数据的类型,instanceof
则是根据函数的prototype
属性值是否存在于对象的原型链上来判断数据的类型。 -
typeof
判断数据类型共有8个值,它们分别是undefined、number、boolean、string、symbol、bigint、object和function
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof []); // object
console.log(typeof function()); // function
console.log(typeof ); // object
console.log(typeof undefined); // undefined
console.log(typeof null); // object
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function() instanceof Function); // true
console.log( instanceof Object); // true
Js 数组常用方法
push()
:数组的末尾追加改变原有数组unshift()
:向数组的开头添加改变原有数组splice()
:向数组的指定index
处插入 返回的是被删除掉的元素的集合,会改变原有数组pop()
:从尾部删除一个元素改变原有数组shift()
:从头部删除一个元素改变原有数组splice()
:在index
处删除多个个元素会改变原有数组reverse()
:反转,倒置 改变原有数组sort()
:按指定规则排序 改变原有数组
constructor(构造函数)
- 当一个函数被定义时,
JS
引擎会为函数添加prototype
属性,然后在prototype
属性上添加一个constructor
属性,并让其指向该函数。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3FeRkqgs-1652746420784)(images/image-20220427201926235.png)]
- 当执行
let a = new method()
时,method
被当成了构造函数,a
是method
的实例对象,此时method
原型上的constructor
属性传递到了a
上,所以a.constructor===method
Js 数据类型转换
- 转换为数字:
Number()、parseInt()、parseFloat()
- 转换为字符串:
.toString()、String()
- 转换为布尔值:
Bollean()
new 操作符的执行过程
- 创建一个新的对象
- 设置原型,将对象的原型设置为函数的
prototype
对象 - 让函数的
this
指向对象,执行构造函数的代码 - 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,返回引用类型的对象。
<script type="text/javascript">
function Animal(name, age)
this.name = name;
this.age = age;
function objectFactory()
let object = null;
let constructor = Array.prototype.shift.call(arguments);
let result = null;
// 判断参数是否是一个函数
if (typeof constructor != "function")
console.error("类型错误");
return;
// 新建一个空对象,对象的原型为构造函数的 proptype 对象
object = Object.create(constructor.prototype);
// 将 this 指向新建对象,并执行函数
result = constructor.apply(object, arguments);
// 判断返回对象
let flag =
result &&
(typeof result === "object" || typeof result === "function");
// 判断返回结果
return flag ? result : object;
const animal = objectFactory(Animal, "Ketty", 20);
console.log(animal);
</script>
let、var、const
- 用
var
声明的变量既是全局变量,也是顶层变量,使用var
,我们能够对一个变量进行多次声明,后面声明的变量会覆盖前面的变量声明。 - 在函数中使用使用
var
声明变量时候,该变量是局部的。 let
是ES6
新增的命令,用来声明变量用法类似于var
,但是所声明的变量,只在let
命令所在的代码块内有效。不存在变量提升。const
声明一个只读的常量,一旦声明,常量的值就不能改变。
Promise
作用
- 主要用于异步计算
- 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
- 可以在对象之间传递和操作promise,帮助我们处理队列
Promise
- promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)
- 并未剥夺函数return的能力,因此无需层层传递callback,进行回调获取数据
- 代码风格,容易理解,便于维护
- 多个异步等待合并便于解决
Promise 状态
pending
[待定]初始状态fulfilled
[实现]操作成功rejected
[被否决]操作失败- 当
promise
状态发生改变,就会触发then()
里的响应函数处理后续步骤; - 从
pending
变为fulfilled
,从pending
变为rejected
。这两种情况只要发生,状态就凝固了,不会再变了。
示例代码1
<body>
<button type="button" onclick="method1()">测试方法1</button>
<script type="text/javascript">
function method1()
new Promise(
function (resolve, reject)
// 一段耗时的异步操作
resolve('成功') // 数据处理完成
// reject('失败') // 数据处理出错
).then(
(res) => console.log(res), // 成功
(err) => console.log(err) // 失败
)
</script>
</body>
resolve
:将Promise
对象的状态从“未完成”变为“成功”(即从pending
变为resolved
),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject
作用是,将Promise
对象的状态从“未完成”变为“失败”(即从pending
变为rejected
),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
箭头函数
ES6
中引入了箭头函数。箭头函数允许我们编写更短的函数
// 原始写法
method1 = function ()
alert("hellow world!")
// Es6 箭头函数
method1 = ()=> alert("箭头函数写法!")
对this指向的影响
- 使用箭头函数没有对
this
的绑定。在常规函数中,关键字 this 表示调用该函数的对象,可以是窗口、文档、按钮或其他任何东西。 - 箭头函数可以访问
this
对象,但这个this
对象指向在定义箭头函数时它时所处的对象(宿主对象),而不是运行时的对象。
var name = 'lisi';
let obj =
name: 'zhangsan',
f1 : () =>
debugger
console.log(this); // window对象
console.log(this.name); // lisi
,
f2 : function()
console.log(this); // obj
console.log(this.name); // zhangsan
,
f2 : function()
console.log(this); // obj
console.log(this.name); // zhangsan
;
obj.f1();
Js 闭包
- 一个函数和对其周围状态(词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包。
- 闭包可以在一个内层函数中访问到其外层函数的作用域。
- 在
JavaScript
中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
词法作用域
method2
创建的局部变量name
,display
函数也可以访问display()
没有自己的局部变量。然而,因为它可以访问到外部函数的变量,所以display()
可以使用父函数method2()
中声明的变量name
。
method2 = function()
let name = "张三"
// display 是内部函数,一个闭包
display = function()
alert(name )
display();
JavaScript
中的函数会形成了闭包。 闭包是由函数以及声明该函数的词法环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量.。- 下面的示例代码中,内部函数
displayName()
在执行前,从外部函数返回。
function makeFunc()
var name = "Mozilla";
function displayName()
alert(name);
return displayName;
var myFunc = makeFunc();
myFunc();
使用场景
- 创建私有变量
- 延长变量的生命周期
优点
- 保护函数内变量的安全,实现封装,防止变量流入其他环境发生命名冲突,造成环境污染。
- 在适当的时候,可以在内存中维护变量并缓存,提高执行效率。
缺点
- 消耗内存:通常来说,函数的活动对象会随着执行上下文环境一起被销毁,但是,由于闭包引用的是外部函数的活动对象,因此这个活动对象无法被销毁,这意味着,闭包比一般的函数需要消耗更多的内存。
- 泄漏内存:在
IE9
之前,如果闭包的作用域链中存在DOM
对象,则意味着该DOM
对象无法被销毁,造成内存泄漏。
Js 变量提升
- 下面的代码输出结果为 2,
JavaScript
不是自上而下执行的语言
a = 2;
var a;
console.log(a);
- 上面的代码会变量提升
var a;
a = 2;
console.log(a);
-
js
会将变量的声明提升到js
顶部执行,对于var a = 2
这种语句,会拆分开,将var a
这步进行提升。 -
变量提升的本质其实是
js
引擎在编译的时候,就将所有的变量声明了,因此在执行的时候,所有的变量都已经完成声明。 -
当有多个同名变量的时候,函数声明会覆盖其他的声明。如果有多个函数声明,则由最后一个函数声明覆盖之前的所有声明。
Proxy
Proxy
代理是一个共通的概念,可以起到拦截的作用。ES6
里将Proxy
标准化了,提供了Proxy
构造函数,用来生成Proxy
实例。
var myHandler =
get: function (target, name)
return name in target ? target[name] : "没有这个属性";
,
;
// proxy 测试
method4 = function ()
var p = new Proxy(, myHandler);
p.a = 1;
p.b = 2;
console.log(p.a); // 1
console.log(p.b); // 2
console.log(p.c); // 没有这个属性
;
语法
let p = new Proxy(target, handler);
target
:需要使用Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。handler
: 一个对象,其属性是当执行一个操作时定义代理的行为的函数(可以理解为某种触发器)。
Js 原型链
js
以原型链的形式,保证函数或对象中的方法、属性可以让向下传递,按照面向对象的说法,这就是继承。而js
通过原型链才得以实现函数或对象的继承。JS
的每个函数在创建的时候,都会生成一个属性prototype
,这个属性指向一个对象,这个对象就是此函数的原型对象
。该原型对象
中有个属性为constructor
,指向该函数。
// 构造函数
function Preson(name, age)
this.name = name;
this.age = age;
// 所有实例共享的公共方法
Preson.prototype.say = function (word)
console.log(`$this.name说:$word`);
const p1 = new Preson('张三', 18); // 创建一个Person实例对象
p1.hasOwnProperty('say') // false 说明不是定义在其本身上的
p1.say('hello world'); // 调用公共方法 打印:张三说:hello world
Proto和Prototype
-
prototype
指向函数的原型对象,这是一个显式原型属性,只有函数才拥有该属性。 -
每个对象都有
_proto_
,它是隐式原型属性,指向了创建该对象的构造函数原型。由于js
中是没有类的概念,而为了实现继承,通过_proto_
将对象和原型联系起来组成原型链,就可以让对象访问到不属于自己的属性。
Js 内存泄漏
全局变量
-
在非严格模式下当引用未声明的变量时,会在全局对象中创建一个新变量。在浏览器中,全局对象将是
window
-
全局变量是根据定义无法被垃圾回收机制收集.需要特别注意用于临时存储和处理大量信息的全局变量。如果必须使用全局变量来存储数据,请确保将其指定为
null
或在完成后重新分配它。
function foo(arg)
bar = "this is a hidden global variable";
function foo()
this.variable = "potential accidental global";
// foo 调用自己,this 指向了全局对象(window)
foo();
垃圾回收机制
Javascript
具有自动垃圾回收机制(GC:Garbage Collecation
),也就是说,执行环境会负责管理代码执行过程中使用的内存- 原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存
标记清除
- 代码示例
var m = 0,n = 19 // 把 m,n,add() 标记为进入环境。
add(m, n) // 把 a, b, c标记为进入环境。
console.log(n) // a,b,c标记为离开环境,等待垃圾回收。
function add(a, b)
a++
var c = a + b
return c
引用计数
- 代码示例
const arr = [1, 2, 3, 4];
console.log('hello world');
- 数组
[1, 2, 3, 4]
是一个值,会占用内存。变量arr
是仅有的对这个值的引用,因此引用次数为1
。尽管后面的代码没有用到arr
,它还是会持续占用内存
防抖节流
防抖
- 在事件被触发
n
秒后再执行回调函数,如果在这n
秒内又被触发,则重新计时。 - 维护一个计时器,规定在
delay
时间后触发函数,但是在delay
时间内再次触发的话,都会清除当前的timer
然后重新设置超时调用,即重新计时。这样一来,只有最后一次操作能被触发。
antiShake = function (func, wait, immediate)
let timeout;
return function ()
// 取消 setTimeout 的定时操作
clearTimeout(timeout);
if (immediate)
// 立即执行
let callNow = !timeout;
timeout = setTimeout(function ()
timeout = null;
, wait);
if (callNow)
func();
else
timeout = setTimeout(func(), wait);
method1 = antiShake(function ()
console.log('点击事件')
, 5000, true);
节流
- 规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。
- 节流是通过判断是否到达一定时间来触发函数,若没到规定时间则使用计时器延后,而下一次事件则会重新设定计时器。
// 节流
throtter = function (cd, time = 3000)
var t = null
return function ()
if (t) return
t = setTimeout(function ()
cd.call(this)
t = null
, time);
method2 = throtter(function ()
console.log('节流')
)
this 指向
-
this
的指向和函数在哪里定义无关,和如何调用有关 -
在方法中,
this
表示该方法所属的对象。 -
如果单独使用,
this
表示全局对象。 -
在函数中,
this
表示全局对象。 -
在函数中,在严格模式下,
this
是未定义的(undefined
)。 -
在事件中,
this
表示接收事件的元素。 -
类似
call()
和apply()
方法可以将this
引用到任何对象。
JS 深浅拷贝
浅拷贝
- 原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响
深拷贝
-
如果是在堆中重新分配内存,拥有不同的地址,但是值是一样的,复制后的对象与原来的对象是完全隔离,互不影响,为 深拷贝。
-
JOSN
对象中的stringify
可以把一个js
对象序列化为一个JSON
字符串,parse
可以把JSON
字符串反序列化为一个js
对象,这两个方法实现的是深拷贝。
const cloneObj = JSON.parse(JSON.stringify(obj))
函数柯里化
- 就是将多变量函数拆解为单变量(或部分变量)的多个函数并依次调用。利用闭包,可以形成一个不销毁的私有作用域,把预先处理的内容都存在这个不销毁的作用域里面,并且返回一个函数,以后要执行的就是这个函数。
// 获取 url
function url(param1)
return function(param2,param3)
return `$param1$param2$param3`
let myurl = url('test1');
let myurl1 = myurl(以上是关于# 技术栈知识点巩固——Js的主要内容,如果未能解决你的问题,请参考以下文章