use strict
1.变量的默认值:声明未赋值
2.数组的越界访问,值为undefined
3.形参的默认值
4.函数的返回值默认为undefined
5.访问对象中不存在的属性,返回undefined(如果是方法那就要报错了)
声明对象1.字面量的方法2.实例化Object() new Object()
break
语句和continue
语句都具有跳转作用,可以让代码不按既有的顺序执行。
break
语句用于跳出代码块或循环。
var i = 0;
while(i < 100) {
console.log('i 当前为:' + i);
i++;
if (i === 10) break;
}
上面代码只会执行10次循环,一旦i
等于10,就会跳出循环。
for
循环也可以使用break
语句跳出循环。
for (var i = 0; i < 5; i++) {
console.log(i);
if (i === 3)
break;
}
// 0
// 1
// 2
// 3
上面代码执行到i
等于3,就会跳出循环。
continue
语句用于立即终止本轮循环,返回循环结构的头部,开始下一轮循环。
var i = 0;
while (i < 100){
i++;
if (i % 2 === 0) continue;
console.log('i 当前为:' + i);
}
上面代码只有在i
为奇数时,才会输出i
的值。如果i
为偶数,则直接进入下一轮循环。
如果存在多重循环,不带参数的break
语句和continue
语句都只针对最内层循环。
JavaScript 语言允许,语句的前面有标签(label),相当于定位符,用于跳转到程序的任意位置,标签的格式如下。
label:
语句
标签可以是任意的标识符,但不能是保留字,语句部分可以是任意语句。
标签通常与break
语句和continue
语句配合使用,跳出特定的循环。
top:
for (var i = 0; i < 3; i++){
for (var j = 0; j < 3; j++){
if (i === 1 && j === 1) break top;
console.log('i=' + i + ', j=' + j);
}
}
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0
上面代码为一个双重循环区块,break
命令后面加上了top
标签(注意,top
不用加引号),满足条件时,直接跳出双层循环。如果break
语句后面不使用标签,则只能跳出内层循环,进入下一次的外层循环。
标签也可以用于跳出代码块。
foo: {
console.log(1);
break foo;
console.log('本行不会输出');
}
console.log(2);
// 1
// 2
上面代码执行到break foo
,就会跳出区块。
continue
语句也可以与标签配合使用。
top:
for (var i = 0; i < 3; i++){
for (var j = 0; j < 3; j++){
if (i === 1 && j === 1) continue top;
console.log('i=' + i + ', j=' + j);
}
}
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0
// i=2, j=0
// i=2, j=1
// i=2, j=2
上面代码中,continue
命令后面有一个标签名,满足条件时,会跳过当前循环,直接进入下一轮外层循环。如果continue
语句后面不使用标签,则只能进入下一轮的内层循环。
null
与undefined
都可以表示“没有”,含义非常相似。将一个变量赋值为undefined
或null
,老实说,语法效果几乎没区别。
var a = undefined;
// 或者
var a = null;
上面代码中,变量a
分别被赋值为undefined
和null
,这两种写法的效果几乎等价。
在if
语句中,它们都会被自动转为false
,相等运算符(==
)甚至直接报告两者相等。
if (!undefined) {
console.log('undefined is false');
}
// undefined is false
if (!null) {
console.log('null is false');
}
// null is false
undefined == null
// true
从上面代码可见,两者的行为是何等相似!谷歌公司开发的 JavaScript 语言的替代品 Dart 语言,就明确规定只有null
,没有undefined
!
既然含义与用法都差不多,为什么要同时设置两个这样的值,这不是无端增加复杂度,令初学者困扰吗?这与历史原因有关。
1995年 JavaScript 诞生时,最初像 Java 一样,只设置了null
表示"无"。根据 C 语言的传统,null
可以自动转为0
。
Number(null) // 0
5 + null // 5
上面代码中,null
转为数字时,自动变成0。
但是,JavaScript 的设计者 Brendan Eich,觉得这样做还不够。首先,第一版的 JavaScript 里面,null
就像在 Java 里一样,被当成一个对象,Brendan Eich 觉得表示“无”的值最好不是对象。其次,那时的 JavaScript 不包括错误处理机制,Brendan Eich 觉得,如果null
自动转为0,很不容易发现错误。
因此,他又设计了一个undefined
。区别是这样的:null
是一个表示“空”的对象,转为数值时为0
;undefined
是一个表示"此处无定义"的原始值,转为数值时为NaN
。
Number(undefined) // NaN
5 + undefined // NaN
对于null
和undefined
,大致可以像下面这样理解。
null
表示空值,即该处的值现在为空。调用函数时,某个参数未设置任何值,这时就可以传入null
,表示该参数为空。比如,某个函数接受引擎抛出的错误作为参数,如果运行过程中未出错,那么这个参数就会传入null
,表示未发生错误。
undefined
表示“未定义”,下面是返回undefined
的典型场景。
// 变量声明了,但没有赋值
var i;
i // undefined
// 调用函数时,应该提供的参数没有提供,该参数等于 undefined
function f(x) {
return x;
}
f() // undefined
// 对象没有赋值的属性
var o = new Object();
o.p // undefined
// 函数没有返回值时,默认返回 undefined
function f() {}
f() // undefined
面向对象编程(Object Oriented Programming,缩写为 OOP)是目前主流的编程范式。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。
每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。对象可以复用,通过继承机制还可以定制。因此,面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的过程式编程(procedural programming),更适合多人合作的大型软件项目。
那么,“对象”(object)到底是什么?我们从两个层次来理解。
(1)对象是单个实物的抽象。
一本书、一辆汽车、一个人都可以是对象,一个数据库、一张网页、一个远程服务器连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。
(2)对象是一个容器,封装了属性(property)和方法(method)。
属性是对象的状态,方法是对象的行为(完成某种任务)。比如,我们可以把动物抽象为animal
对象,使用“属性”记录具体是哪一种动物,使用“方法”表示动物的某种行为(奔跑、捕猎、休息等等)。
面向对象编程的第一步,就是要生成对象。前面说过,对象是单个实物的抽象。通常需要一个模板,表示某一类实物的共同特征,然后对象根据这个模板生成。
典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念。所谓“类”就是对象的模板,对象就是“类”的实例。但是,JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。
JavaScript 语言使用构造函数(constructor)作为对象的模板。所谓”构造函数”,就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构。
构造函数就是一个普通的函数,但具有自己的特征和用法。
var Vehicle = function () {
this.price = 1000;
};
上面代码中,Vehicle
就是构造函数。为了与普通函数区别,构造函数名字的第一个字母通常大写。
构造函数的特点有两个。
this
关键字,代表了所要生成的对象实例。new
命令。下面先介绍new
命令。
new
命令的作用,就是执行构造函数,返回一个实例对象。
var Vehicle = function () {
this.price = 1000;
};
var v = new Vehicle();
v.price // 1000
上面代码通过new
命令,让构造函数Vehicle
生成一个实例对象,保存在变量v
中。这个新生成的实例对象,从构造函数Vehicle
得到了price
属性。new
命令执行时,构造函数内部的this
,就代表了新生成的实例对象,this.price
表示实例对象有一个price
属性,值是1000。
使用new
命令时,根据需要,构造函数也可以接受参数。
var Vehicle = function (p) {
this.price = p;
};
var v = new Vehicle(500);
new
命令本身就可以执行构造函数,所以后面的构造函数可以带括号,也可以不带括号。下面两行代码是等价的,但是为了表示这里是函数调用,推荐使用括号。
// 推荐的写法
var v = new Vehicle();
// 不推荐的写法
var v = new Vehicle;
一个很自然的问题是,如果忘了使用new
命令,直接调用构造函数会发生什么事?
这种情况下,构造函数就变成了普通函数,并不会生成实例对象。而且由于后面会说到的原因,this
这时代表全局对象,将造成一些意想不到的结果。
var Vehicle = function (){
this.price = 1000;
};
var v = Vehicle();
v // undefined
price // 1000
上面代码中,调用Vehicle
构造函数时,忘了加上new
命令。结果,变量v
变成了undefined
,而price
属性变成了全局变量。因此,应该非常小心,避免不使用new
命令、直接调用构造函数。
为了保证构造函数必须与new
命令一起使用,一个解决办法是,构造函数内部使用严格模式,即第一行加上use strict
。这样的话,一旦忘了使用new
命令,直接调用构造函数就会报错。
function Fubar(foo, bar){
'use strict';
this._foo = foo;
this._bar = bar;
}
Fubar()
// TypeError: Cannot set property '_foo' of undefined
上面代码的Fubar
为构造函数,use strict
命令保证了该函数在严格模式下运行。由于严格模式中,函数内部的this
不能指向全局对象,默认等于undefined
,导致不加new
调用会报错(JavaScript 不允许对undefined
添加属性)。
另一个解决办法,构造函数内部判断是否使用new
命令,如果发现没有使用,则直接返回一个实例对象。
function Fubar(foo, bar) {
if (!(this instanceof Fubar)) {
return new Fubar(foo, bar);
}
this._foo = foo;
this._bar = bar;
}
Fubar(1, 2)._foo // 1
(new Fubar(1, 2))._foo // 1
上面代码中的构造函数,不管加不加new
命令,都会得到同样的结果。
使用new
命令时,它后面的函数依次执行下面的步骤。
prototype
属性。this
关键字。也就是说,构造函数内部,this
指的是一个新生成的空对象,所有针对this
的操作,都会发生在这个空对象上。构造函数之所以叫“构造函数”,就是说这个函数的目的,就是操作一个空对象(即this
对象),将其“构造”为需要的样子。
如果构造函数内部有return
语句,而且return
后面跟着一个对象,new
命令会返回return
语句指定的对象;否则,就会不管return
语句,返回this
对象。
var Vehicle = function () {
this.price = 1000;
return 1000;
};
(new Vehicle()) === 1000
// false
上面代码中,构造函数Vehicle
的return
语句返回一个数值。这时,new
命令就会忽略这个return
语句,返回“构造”后的this
对象。
但是,如果return
语句返回的是一个跟this
无关的新对象,new
命令会返回这个新对象,而不是this
对象。这一点需要特别引起注意。
var Vehicle = function (){
this.price = 1000;
return { price: 2000 };
};
(new Vehicle()).price
// 2000
上面代码中,构造函数Vehicle
的return
语句,返回的是一个新对象。new
命令会返回这个对象,而不是this
对象。
另一方面,如果对普通函数(内部没有this
关键字的函数)使用new
命令,则会返回一个空对象。
function getMessage() {
return 'this is a message';
}
var msg = new getMessage();
msg // {}
typeof msg // "object"
上面代码中,getMessage
是一个普通函数,返回一个字符串。对它使用new
命令,会得到一个空对象。这是因为new
命令总是返回一个对象,要么是实例对象,要么是return
语句指定的对象。本例中,return
语句返回的是字符串,所以new
命令就忽略了该语句。
new
命令简化的内部流程,可以用下面的代码表示。
function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {
// 将 arguments 对象转为数组
var args = [].slice.call(arguments);
// 取出构造函数
var constructor = args.shift();
// 创建一个空对象,继承构造函数的 prototype 属性
var context = Object.create(constructor.prototype);
// 执行构造函数
var result = constructor.apply(context, args);
// 如果返回结果是对象,就直接返回,否则返回 context 对象
return (typeof result === 'object' && result != null) ? result : context;
}
// 实例
var actor = _new(Person, '张三', 28);
函数内部可以使用new.target
属性。如果当前函数是new
命令调用,new.target
指向当前函数,否则为undefined
。
function f() {
console.log(new.target === f);
}
f() // false
new f() // true
使用这个属性,可以判断函数调用的时候,是否使用new
命令。
function f() {
if (!new.target) {
throw new Error('请使用 new 命令调用!');
}
// ...
}
f() // Uncaught Error: 请使用 new 命令调用!
上面代码中,构造函数f
调用时,没有使用new
命令,就抛出一个错误。
构造函数作为模板,可以生成实例对象。但是,有时拿不到构造函数,只能拿到一个现有的对象。我们希望以这个现有的对象作为模板,生成新的实例对象,这时就可以使用Object.create()
方法。
var person1 = {
name: '张三',
age: 38,
greeting: function() {
console.log('Hi! I\'m ' + this.name + '.');
}
};
var person2 = Object.create(person1);
person2.name // 张三
person2.greeting() // Hi! I'm 张三.
上面代码中,对象person1
是person2
的模板,后者继承了前者的属性和方法。
Object.create()
的详细介绍,请看后面的相关章节。
属性:innerWidth用来获取浏览器的宽度 innerHeight获取浏览器的高度
方法:alert(),prompt(),open(),close()
1.获取元素
2.添加事件
3.实现功能
var date = new Date();
console.log(date); //Wed Jun 15 2022 22:42:49 GMT+0800 (香港标准时间)
date = +new Date();
date = Date.now(); //h5
// var last_date = new Date('2022-6-15 8:0:0')
var last_date = +new Date('2022-6-15 22:59:0');
console.log(date); //1655304449126
console.log(last_date); //1655305140000
var count = last_date - date;
console.log(count); //609200 这是毫秒数
// 时分秒 1时 = 60 分 = 60000ms; 1分 = 1000ms
// h = count % 60000;
// console.log(h);
count = count / 1000;
d = parseInt(count / 60 / 60 / 24);
h = parseInt((count / 60 / 60) % 24);
m = parseInt((count / 60) % 60);
s = parseInt(count % 60);
console.log(d, h, m, s);
setInterval(() => {
var date = Date.now(); //h5
// var last_date = new Date('2022-6-15 8:0:0')
var last_date = +new Date('2022-6-15 22:59:0');
console.log(date); //1655304449126
console.log(last_date); //1655305140000
var count = last_date - date;
console.log(count); //609200 这是毫秒数
// 时分秒 1时 = 60 分 = 60000ms; 1分 = 1000ms
// h = count % 60000;
// console.log(h);
count = count / 1000;
d = parseInt(count / 60 / 60 / 24);
h = parseInt((count / 60 / 60) % 24);
m = parseInt((count / 60) % 60);
s = parseInt(count % 60);
// console.log(d, h, m, s);
console.log(`距离2022-6-15 22:59:0还有: ${d}天 ${h}小时 ${m}分 ${s}秒`);
var time = document.querySelector('.count_down');
time.innerHTML = `距离2022-6-15 22:59:0还有: ${d}天 ${h}小时 ${m}分 ${s}秒`;
}, 1000);
div.onclick=()=>{
}
document.querySelector()
onclick 点击
onmouseover 鼠标进过
onmouseout 鼠标离开
onfocus 获得焦点
onblur 失去焦点
onmousemove 鼠标移动
onmouseup 鼠标弹起
onmousedown 鼠标按下
var one = document.querySelector('.one');
// 获取元素内容
console.log(one.innerHTML);
// 设置新的内容
one.innerHTML = '文本
';
one.innerText;
console.log(one.innerText);
one.innerText = '文本
';
// innerHTML 可以获取元素对象内容 设置元素对象内容 可以识别标签
// innerText 可以获取元素对象内容 设置元素对象内容 不识别标签
// html常见属性 (标签上的常见属性)
/*
id class ...
src,href,title,alt...
表单中: type,placeholder,value,checked,selected
*/
/* 操作html
1.获取属性值
2.操作属性值
*/
// 获取元素
var one = document.querySelector('[type=text');
console.log(one);
// 1.获取属性值 对象.属性名
console.log(one.type); //text
// 2.设置属性值 对象。属性名= 值
one.placeholder = '请输入用户名';
one.type = 'password';
<span class="two" two="1"></span>
var two = document.querySelector('.two');
console.log(two);
// 设置自定义属性的值
two.setAttribute('two', '123');
console.log(two);
// 获取自定义属性的值
two.getAttribute('two');
console.log(two.getAttribute('two'));
// 移除自定义属性
two.removeAttribute('two')
console.log(two);
单独设置:元素.style.css属性名= css属性值(小驼峰)
// 操作css样式
// 单独设置
// 元素.style.css属性名= css属性值(小驼峰)
var text = document.querySelector('.text');
console.log(text);
// 只获取一个元素
text.style.color = 'red';
// 如果有多个元素 就得 元素[key]
var textAll = document.querySelectorAll('.text');
textAll[0].style.fontSize = '30px';
textAll.forEach((item, index) => {
console.log(index);
console.log(item);
item.style.backgroundColor = 'pink';
});
批量操作:
增加类名:classList.add(‘text1’),
移除类名:classList.remove(‘text1’)
// 操作css样式
// 单独设置
// 元素.style.css属性名= css属性值(小驼峰)
var text = document.querySelector('.text');
console.log(text);
// 只获取一个元素
text.style.color = 'red';
// 如果有多个元素 就得 元素[key]
var textAll = document.querySelectorAll('.text');
textAll[0].style.fontSize = '30px';
textAll.forEach((item, index) => {
console.log(index);
console.log(item);
item.style.backgroundColor = 'pink';
});
// 批量
console.log(textAll[0].dir);
textAll[0].classList;
console.log(textAll[0].classList);
textAll[0].classList.add('text1');
textAll[0].classList.add('text2');
console.log(textAll[0].classList);
textAll[0].classList.remove('text1');
console.log(textAll[0].classList);
textAll.forEach((v, i) => {
// 添加类
v.classList.add('one');
console.log(textAll[i]);
});
BOM对象;
innerWidth, innerHeight;
// 定时器
setInterval(() => {
// 函数 回调函数
}, 时间);
clearInterval(定时器名字);
window.setTimeout(() => {
回调;
}, time);
clearTimeout(定时器名字);
window.document;
window.history;
indow.location; //(地址对象)
window.screen; //屏幕对象
window.console; //控制台对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.box {
position: relative;
width: 400px;
border-bottom: 1px solid #ccc;
margin: 100px auto;
}
.box img {
position: absolute;
top: 2px;
right: 2px;
}
.box input {
width: 370px;
height: 30px;
border: 0;
/* 鼠标点击的时候没有边框 */
outline: none;
}
</style>
</head>
<body>
<div class="box">
<input type="password" placeholder="请输入密码" />
<img src="./img/close.png" alt="" width="20px" />
</div>
<!-- <img src="./img/open.png" alt="" /> -->
</body>
</html>
<script>
// 获取元素
var ipt = document.querySelector('input');
var img = document.querySelector('img');
var focus = 1;
// 添加事件
img.onclick = () => {
if (focus == 1) {
img.src = './img/open.png';
ipt.type = 'text';
focus = 0;
} else if (focus == 0) {
img.src = './img/close.png';
ipt.type = 'password';
focus = 1;
}
};
</script>
var lis = document.querySelectorAll('li');
// 用let声明变量 let有局部作用域
// 或者使用forEach
for (let i = 0; i < lis.length; i++) {
console.log(i);
lis[i].onclick = function () {
// 让所有人的元素都恢复为默认状态 干掉其他人
// console.log(lis[i]);
for (let j = 0; j < lis.length; j++) {
// const element = lis[j];
lis[j].classList.remove('item');
// lis[j].style.backgroundColor = '#000';
// lis[j].style.color = '#fff';
}
console.log(i);
// lis[i].style.backgroundColor = '#ff6700';
// lis[i].style.color = 'blue';
// 给当前元素添加选中状态 留下我自己
lis[i].classList.add('item');
};
}
var lis = document.querySelectorAll('li');
console.log(lis);
for (let i = 0; i < lis.length; i++) {
lis[i].onmouseover = () => {
for (let j = 0; j < lis.length; j++) {
lis[j].classList.remove('pink');
}
lis[i].classList.add('pink');
};
}
var h1 = document.querySelector('h1')
console.log(h1);
// 属性
var one = h1.parentNode
console.log(one);
console.log();
var all = one.childNodes
console.log(all);
console.log(one.childNodes[1]);
console.log(one.children);//HTMLCollection(7) [h1, p, span, a, ul, script, script] *****
console.log(one.firstChild);
console.log(one.firstElementChild);//返回第一个子元素节点 找不到 就返回 null ****** 这俩有兼容性 IE9+
console.log(one.lastElementChild);//返回最后一个子元素节点 找不到返回 null ******
console.log(one.children[0]);
console.log(one.children[one.length - 1]);
one.nextSibling //下一个兄弟 所有节点
console.log(h1.nextElementSibling);//h1的下一个兄弟元素节点
var h2 = document.createElement('h2') //动态创建元素节点 参数是'标签名'
console.log(h2);
// 添加内容 属性 样式 等
h2.innerHTML = '我是h2'
h2.style.color = 'red'
document.body.appendChild(h2) // 在某个节点中 插入节点 在末尾插入
document.body.insertBefore(h2,h1) // insertBefore(插入内容,指定元素) 把插入内容 插入到 指定元素之前 ***********************
// 创建元素之后并没有插入到页面中
// 节点包括 元素节点 属性节点 文本节点 注释节点
/*
父节点 h1.parentNode
对象.parentNode (最近的父节点)
子节点 父节点.parentNodes
返回所有的子节点 包括元素节点和文本节点等
父节点.children 获取所有的元素节点
one.children
父节点.firstElementChild 获得第一个子元素节点
兄弟节点
*/
// 方法
/*
事件三要素 事件 事件源 事件处理函数
面试题 new关键字 作用域连 js事件监听的兼容性问题
注册事假你的方式 on+type,事件监听(兼容性问题)
事件流 捕获阶段(从顶向上 )div.addEventListener('click',function name(params) {
},true)
处理阶段
冒泡阶段 on+type add true
事件对象 鼠标 键盘
事件委派:冒泡 的应用
// 事件委派 操作dom一次 添加到ul(父元素)中
将事件添加到父元素身上,通过e.target判断
事件委派 应用场景:()
1.大量元素添加事件 你就要进行若干次的dom操作 为了提高性能减少DOM操作 就要委派
2.动态创建的元素 如果不刷新就不重新获取元素 就获取不到元素
*/
事件流的三个阶段 :捕获阶段,目标阶段,冒泡阶段
捕获型事件流:从顶层元素开始,逐级向下,直到最具体的元素
addEVentListener(‘‘事件’’,函数,true)
冒泡型事件流:从最具体的元素开始 逐级向上执行 直到顶层元素
on+Type,addEVentListener(‘‘事件’’,函数,false)
阻止冒泡
var father = document.querySelector('.father')
var son = document.querySelector('.son')
father.addEventListener('click', () => {
console.log(father);
console.log('father');
})
// son.onclick = () => {
// console.log(son);
// console.log('son');
// }
son.addEventListener('click', (e) => {
e.stopPropagation() //阻止冒泡
console.log('son');
})
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-skHQ5Do4-1658243579335)(C:\Users\86135\AppData\Roaming\Typora\typora-user-images\image-20220618105247690.png)]
* 1.任何情况下直接在script中写入的this都是window。
* 2.函数中的this 非严格模式:this指向window, 严格模式时:this指向undefined。
* 3.箭头函数的this
this都指向箭头函数外上下文环境的this指向
* 4.对象中this
对象属性的this 指向对象外上下文环境的this
对象方法(普通函数)中的this,指向当前对象(谁执行该方法,this就指向谁)
* 5.回调函数的this指向
* 1)、 setTimeout,setInterval回调函数不管是否是严格模式都会指向window。
* 2)、通过在函数内执行当前回调函数 非严格模式:this指向window, 严格模式时:this指向undefined。
* 3)递归函数中的this 非严格模式:this指向window, 严格模式时:this指向undefined。
* 4) 使用arguments[0]()执行函数时 this指向arguments。
* 5)事件中的回调函数,this指向事件侦听的对象(e.currentTarget);
* 6、call,apply,bind方法执行时this的指向
* 如果call,apply,bind传参时,第一个参数传入的不是null或者undefined,传入什么this指向什么
* 如果第一个参数传入的是null或者undefined ,非严格模式下指向window
* 7、在ES6的类中this的指向
* 构造函数中的this指向实例当前类所产生的新的实例对象
* 类中实例化方法中this指向谁执行该方法,this指向谁
* 类中静态方法中this执行该类或者该类的构造函数
* 类中实例化箭头方法,this仍然指向当前类实例化的实例对象
* 8、ES5的原型对象中this的指向
* 在原型的方法中,this指向实例化当前构造函数的实例化对象(谁执行该方法,this指向谁);
* 三种改变this指向的方式
* 函数名.call(this,....)this写谁就指谁。
* 函数名.apply(this,[参数1,参数2,...]) this写谁就指谁。
* 函数名. bind (this,1,2,3) this写谁就指谁。
* 构造函数中的this指向实例当前类所产生的新的实例对象
* 类中实例化方法中this指向谁执行该方法,this指向谁
* 类中静态方法中this执行该类或者该类的构造函数
* 类中实例化箭头方法,this仍然指向当前类实例化的实例对象、
// 1.全局作用域 普通函数
console.log(this);
function fn() {
console.log(this);
}
fn()
// 在方法调用中 谁使用就指向谁
div = document.querySelector('div')
div.onclick = function () {
console.log(this); //点击
}
// 3.构造函数 this 指向构造函数的实例化的那个对象
function Cup(size) {
this.size = size
console.log(this); //Cup {size: '1000'}
}
var myCup = new Cup('1000')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ajax
</title>
<style>
div {
width: 200px;
height: 200px;
border: 1px solid #000;
background-color: pink;
}
</style>
</head>
<body>
<button>点击</button>
<div>
</div>
</body>
</html>
<script>
var btn = document.querySelector('button')
var div = document.querySelector('div')
btn.onclick = function () {
// console.log(1);
// 1.穿件对象
var xhr = new XMLHttpRequest()
// 2.初始化 设置请求类型和请求地址
// 如果有参数
xhr.open('GET', 'http://127.0.0.1:8080/server?username=123')
// xhr.open('GET', 'http://127.0.0.1:8080/server')
// 3.发送请求
xhr.send()
// 4.绑定事件进行监听 处理服务端返回的结果(响应报文)
// readystate 是xhr身上的一个属性,记录了客户端向服务器发送请求的状态
// 0 为初始化 1 完成open 2send 3服务器数据部分返回 4服务器数据全部返回
xhr.onreadystatechange = function () {
// 服务器全部返回了结果
if (xhr.readyState == 4) {
// 判断响应的状态码status
if (xhr.status == 200) {
// 响应报文 响应行(状态码 状态描述) 响应头 响应体
console.log(xhr.status); //状态码
console.log(xhr.statusText); //状态描述
xhr.response
console.log(xhr.response); //响应体
// 发生了跨越问题(同源策略:协议域名端口号全部一致) 解决跨域
div.innerHTML = xhr.response
}
}
}
}
</script>
app.get('/server', (req, res) => {
/* 解决跨域问题 设置响应头允许跨域访问 */
res.setHeader('Access-Control-Allow-Origin', '*');
res.send('server-get');
});
2.post请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
height: 200px;
width: 200px;
background-color: pink;
}
</style>
</head>
<body>
<button>post</button>
<div></div>
</body>
</html>
<script>
var btn = document.querySelector('button')
var div = document.querySelector('div')
// onmouseenter
btn.onclick = function () {
// 穿件对象
var xhr = new XMLHttpRequest()
xhr.open('post', 'http://127.0.0.1:8080/server')
// 设置请求头 客户端告诉浏览器实际发送的内容
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 通过xhr.send发送数据
xhr.send('username="zs"&password=12456')
xhr.onreadystatechange = function () {
// 传完数据
if (xhr.readyState == 4) {
// 服务器响应成功
if (xhr.status == 200) {
div.innerHTML = xhr.response
var res = JSON.parse(xhr.response)
console.log(res.code);
console.log(res.msg);
}
}
}
}
</script>
const express = require('express');
const app = express();
// 配置内置中间件解析post的请求数据
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.get('/server', (req, res) => {
/* 解决跨域问题 设置响应头允许跨域访问 */
res.setHeader('Access-Control-Allow-Origin', '*');
res.send('server-get');
});
app.post('/server', (req, res) => {
console.log(req.body);
/* 解决跨域问题 设置响应头允许跨域访问 */
res.setHeader('Access-Control-Allow-Origin', '*');
//我想返回一个数据
var data = { code: 1, msg: '请求成功' };
JSON.stringify(data);
res.send(JSON.stringify(data));
// res.send('server-post');
// 配置post解析数据之后 返魂一个空对象 ,需要给他一个请求头信息
// xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
//
});
app.listen(8080, () => {
console.log('http://127.0.0.1:8080');
});
/*
post请求注意事项
1.所请求的路由必须在路由中注册才可以
2.要解决跨域问题
res.setHeader('Access-Control-Allow-Origin', '*');
3.在html页面中 请求的数据要存在 xhr.send('username="admin"&password=12456')
4.在html要设置请求头部信息 一般是xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
5.用Ajax异步发请求
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
div.innerHTML = xhr.response
var res = JSON.parse(xhr.response)
console.log(res);
console.log(res.code);
console.log(res.msg);
}
}
}
6.readyState
ajax.readyState:
0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send()方法,正在发送请求
2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成,可以在客户端调用了
7.HTTP 状态码 ajax.status
101——客户要求服务器根据请求转换HTTP协议版本
200——交易成功
304——客户端已经执行了GET,但文件未变化
306——前一版本HTTP中使用的代码,现行版本中不再使用
400——错误请求,如语法错误
404——没有发现文件、查询或UR
405——用户在Request-Line字段定义的方法不允许
500——服务器产生内部错误
505——服务器不支持或拒绝支请求头中指定的HTTP版本
7.JSON数据的传输 服务器传给页面要传字符串格式的JSON数据
然后页面反序列为对象格式数据从而使用
*/
路由中配置静态文件和模板引擎 配置路由body
//导入ejs和
const ejs = require('ejs');
const path = require('path');
// 配置静态文件
app.use(express.static('static'));
// 配置模板引擎
// 设置模板存储的位置
app.set('views', path.join(__dirname, 'views'));
// 设置模板存储位置
app.set('view engine', 'html');
// 使用ejs模板引擎解析
app.engine('html', require('ejs').renderFile);
// 配置路由body
app.use(express.urlencoded({ extended: false }));
app.use(express.json());