技术栈知识点巩固——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);
console.log(typeof true);
console.log(typeof 'str');
console.log(typeof []);
console.log(typeof function(){});
console.log(typeof {});
console.log(typeof undefined);
console.log(typeof null);
console.log(2 instanceof Number);
console.log(true instanceof Boolean);
console.log('str' instanceof String);
console.log([] instanceof Array);
console.log(function(){} instanceof Function);
console.log({} instanceof Object);
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;
}
object = Object.create(constructor.prototype);
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('成功')
}
).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!")
}
method1 = ()=> alert("箭头函数写法!")
对this指向的影响
- 使用箭头函数没有对
this 的绑定。在常规函数中,关键字 this 表示调用该函数的对象,可以是窗口、文档、按钮或其他任何东西。 - 箭头函数可以访问
this 对象,但这个this 对象指向在定义箭头函数时它时所处的对象(宿主对象),而不是运行时的对象。
var name = 'lisi';
let obj = {
name: 'zhangsan',
f1 : () => {
debugger
console.log(this);
console.log(this.name);
},
f2 : function(){
console.log(this);
console.log(this.name);
},
f2 : function(){
console.log(this);
console.log(this.name);
}
};
obj.f1();
Js 闭包
- 一个函数和对其周围状态(词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包。
- 闭包可以在一个内层函数中访问到其外层函数的作用域。
- 在
JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
词法作用域
method2 创建的局部变量name ,display 函数也可以访问display() 没有自己的局部变量。然而,因为它可以访问到外部函数的变量,所以 display() 可以使用父函数 method2() 中声明的变量 name 。
method2 = function(){
let name = "张三"
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] : "没有这个属性";
},
};
method4 = function () {
var p = new Proxy({}, myHandler);
p.a = 1;
p.b = 2;
console.log(p.a);
console.log(p.b);
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);
p1.hasOwnProperty('say')
p1.say('hello world');
Proto和Prototype
Js 内存泄漏
全局变量
function foo(arg) {
bar = "this is a hidden global variable";
}
function foo() {
this.variable = "potential accidental global";
}
foo();
垃圾回收机制
Javascript 具有自动垃圾回收机制(GC:Garbage Collecation ),也就是说,执行环境会负责管理代码执行过程中使用的内存- 原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存
标记清除
var m = 0,n = 19
add(m, n)
console.log(n)
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 () {
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 深浅拷贝
浅拷贝
- 原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响
深拷贝
const cloneObj = JSON.parse(JSON.stringify(obj))
函数柯里化
- 就是将多变量函数拆解为单变量(或部分变量)的多个函数并依次调用。利用闭包,可以形成一个不销毁的私有作用域,把预先处理的内容都存在这个不销毁的作用域里面,并且返回一个函数,以后要执行的就是这个函数。
function url(param1){
return function(param2,param3){
return `${param1}${param2}${param3}`
}
}
let myurl = url('test1');
let myurl1 = myurl('test2','test3')
let myurl2 = myurl('test4')
Ajax 请求
- 当程序执行到
Ajax 代码时,将 Ajax 代码交给另外一个线程来执行,不论执行结果如何,当前线程会继续向下执行。
工作原理
JavaScript 需要使用浏览器内置的 XMLHttpRequest 对象向服务器发送 HTTP 请求,并接收服务器响应的数据。
发送Ajax请求
<!DOCTYPE html>
<html>
<body>
<div id="result"></div>
<button type="button" onclick="displayFullName()">点击发送请求</button>
<script type="text/javascript">
displayFullName = function() {
var request = new XMLHttpRequest();
request.open('post', 'http://127.0.0.1:8000/test');
request.onreadystatechange = function() {
debugger
if(this.readyState === 4 && this.status === 200) {
document.getElementById("result").innerHTML = this.responseText;
}else {
document.getElementById("result").innerHTML = '请求失败';
}
};
request.send()
}
</script>
</body>
</html>
displayFullName2 = function() {
$.ajax({
url: 'http://127.0.0.1:8000/test',
type: 'post',
dataType:'',
data:{
param1:'test1',
param2:'test2'
},
success:function(){
alert('成功')
},
error: function () {
alert('失败')
}
})
}
参数说明
method :请求的类型(使用的 HTTP 方法),例如 GET、POST、PUT、HEAD、DELETE 等url :请求的地址async :可选参数,布尔类型,表示是否请求是否异步执行,默认值为 trueuser :可选参数,表示用户名,主要用来认证,默认值为 null password :可选参数,表示密码,同样用来认证,默认值为 null
Call、Apply、Bind
call 、apply 、bind 作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this 指向
示例代码
var name = "lucy";
var obj = {
name: "martin",
say: function () {
console.log(this.name);
}
};
obj.say();
setTimeout(obj.say,0);
setTimeout(obj.say.bind(obj),0);
区别
- 三者都可以改变函数的
this 对象指向。 - 三者第一个参数都是
this 要指向的对象,如果如果没有这个参数或参数为undefined 或null ,则默认指向全局window 。 - 三者都可以传参,但是
apply 是数组,而call 是参数列表,且apply 和call 是一次性传入参数,而bind 可以分为多次传入。 bind 是返回绑定this 之后的函数,便于稍后调用;apply 、call 则是立即执行 。
Apply
fn.apply(obj,[1,2]);
fn(1,2)
Call
fn.call(null,[1,2]);
fn.call(undefined,[1,2]);
Bind
bind 方法和call 很相似,第一参数也是this 的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)
改变this 指向后不会立即执行,而是返回一个永久改变this 指向的函数
Map、Set
var m = new Map();
m.set('Adam', 67);
m.set('Bob', 59);
m.has('Adam');
m.get('Adam');
m.delete('Adam');
m.get('Adam');
var s1 = new Set();
var s2 = new Set([1, 2, 3]);
foreach
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
alert(element);
});
== 和 === 区别
- 除了在比较对象属性为
null 或者undefined 的情况下,我们可以使用相等操作符== ,其他情况建议一律使用全等操作符===
等于操作符
- 两个都为简单类型,字符串和布尔值都会转换成数值,再比较
- 简单类型与引用类型比较,对象转化成其原始类型的值,再比较
- 两个都为引用类型,则比较它们是否指向同一个对象
null 和 undefined 相等- 存在
NaN 则返回 false
全等操作符
- 全等操作符由 3 个等于号
=== 表示,只有两个操作数在不转换的前提下相等才返回 true 。即类型相同,值也需相同
事件循环
JavaScript 是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环
同步任务
异步任务
- 异步执行的任务,比如
ajax 网络请求,setTimeout 定时函数等
async
test3 = function(){
return Promise.resolve('test')
}
async function test4 (){
return 'test'
}
await
- 正常情况下,
await 命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值 - 不管
await 后面跟着的是什么,await 都会阻塞后面的代码
async function test5(){
return await 123
}
test5().then(res=>console.log(res))
JavaScript 实现继承
function Animal(name){
this.name = name;
this.sayName = function() {
window.alert(this.name);
};
}
借用构造函数(经典继承)
function Cat(name,age){
Animal.call(this,name)
this.age = age
}
createcat = function(){
let cat = new Cat('Ketty',16);
cat.sayName();
}
对象冒充
function Dog(name,age){
this.animal = Animal
this.animal(name)
}
组合继承
function Car(name){
this.name = name
}
Car.prototype = {
sayName:function(){
window.alert(this.name+'----'+this.sno)
}
}
function Hongqi(name,sno){
Car.call(this,name)
this.sno = sno
}
Hongqi.prototype = new Car();
createobject1 = function () {
let hongqi = new Hongqi('hongqi',1001);
hongqi.sayName();
}
回调函数
- 回调函数是一段可执行的代码段,它作为一个参数传递给其他的代码,其作用是在需要的时候方便调用这段(回调函数)代码。
回调函数
function sayHellow(msg, callback) {
alert(msg)
if (typeof callback === "function") {
callback(msg);
}
}
function one(msg){
alert(msg)
}
sayHellow('你好',one);
匿名回调函数
function sayHellow(msg, callback) {
alert(msg)
if (typeof callback === "function") {
callback();
}
}
sayHellow('你好', function () {
alert('匿名函数实现回调')
})
使用注意事项
- 不会立刻执行:传递的是函数的定义不会立即执行,回调函数在函调用函数中也要通过
() 运算符调用才会执行。 - 是个闭包:回调函数是一个闭包,也就是说它能访问到其外层定义的变量。
- 执行前类型判断:在执行回调函数前最好确认其是一个函数。
this 使用:在回调函数调用时this的执行上下文并不是回调函数定义时的那个上下文,而是调用它的函数所在的上下文- 允许传递多个回调函数
扩展运算符
method4 = function () {
let item = { a: 1, b: 2, c: 3, d: 4 };
let obj1 = { ...item };
let obj2 = Object.assign({}, item);
};
对象与数组的解构
- 解构是
ES6 提供的一种新的提取数据的模式,这种模式能够从对象或数组里有针对性地拿到想要的数值。
const [a,b,c] = [1,2,3]
let item = {a:'test1',b:'test2'}
const {a,b} = item
|