零.前言
JavaScript(一)---【js的两种导入方式、全局作用域、函数作用域、块作用域】-CSDN博客
JavaScript(二)---【js数组、js对象、this指针】-CSDN博客
0.1全局对象
在JS中有一个全局对象:“window object”,代指的是整个HTML。
一定要慎用全局对象,因为太容易导致程序崩溃了。
一.this指针
this指针所代指的目标,取决于它所在的位置,一般来说它有如下几种情况:
- 在对象方法中,this指的是“对象”
- 在单独的情况下,this指的是全局对象
- 在函数中,this指的是全局对象
- 在事件中,this指的是接受事件的元素
下面我们将挨个对上述情况进行实验:
1.1对象方法中的this指针
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var thisPoint = {
firstName : "ju",
lastName : "jingyi",
myThis : function(){
return this.firstName + this.lastName;
}
};
console.log(thisPoint.myThis());
</script>
</body>
</html>
效果:
1.2单独情况下的this指针
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var x = this;
console.log(x);
</script>
</body>
</html>
效果:
1.3函数中的this指针
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function myThis(){
return this;
}
console.log(myThis())
</script>
</body>
</html>
效果:
1.4事件中的this指针
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>按钮前的位置</h1>
<button onclick="this.style.display='none'">点击来删除我!</button>
<h1>按钮后的位置</h1>
</body>
</html>
效果:
点击前:
点击后:
二.函数定义
2.1正常的函数定义
非常简单,格式如下:
function myFunction(a, b) {
return a * b;
}
“function”代表是一个函数关键字,“myFunction”是函数名字,“(a,b)”是函数形参
2.2使用函数表达式定义
函数表达式就是“函数定义”的样式
例如:“function (a, b) {return a * b}”就是一个函数表达式,函数表达式没有名字。
对于没有名字的函数,我们也叫作“匿名函数”。
匿名函数(函数表达式)的应用多用于存放在变量中,用变量来调用函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
x = function (a,b) {return a + b};
console.log(x(1,2))
</script>
</body>
</html>
效果:
根据这个特性,我们还可以结合“不加()调用函数,返回函数的定义”,来实现更高效的开发:
<script>
var x = sample;
function sample(a,b){
return a + b;
};
console.log(x(1,2));
</script>
2.3自调用函数
函数表达式可以作为“自调用”
自调用函数无需人为的调用,它会在被定义完成后自动执行
同时自调用函数,人为调用是禁止的
使用方法:“在函数的最后添加括号()”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
x = function () {return 1 + 2}(); //自调用函数,x被赋予自调用函数返回值3
console.log(x)
</script>
</body>
</html>
当自调用函数不是匿名函数时,需要给自调用函数外围添加一个"括号包围起来,再加一个括号"。
<script>
var x;
(function sample(){
x = 100;
})();
console.log(x);
</script>
效果:
2.4箭头函数
箭头函数用来简写函数表达式(偷懒用的)
使用箭头函数,我们不需要书写:“function关键字”、“return关键字”、“花括号”(个人推荐写上,容易歧义)
使用方法:
形参列表 => {函数内容}
一定注意,要写上:“=>”,否则函数无效!
<script>
x = (a,b) => a * b;
console.log(x(2,5));
</script>
效果:
当然推荐写上“花括号”
<script>
x = (a,b) => {a * b};
console.log(x(2,5));
</script>
注意:
如果在对象中使用“箭头函数”做方法是禁止的,因为“箭头函数”没有this指针!!
三.函数参数
3.1arguments对象
在JS函数中有一个arguments内置对象,包含了函数调用时的所有形参,并以数组的形式呈现。
这样可以很方便的使我们遍历形参,从而达成某种目的。
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function Print(x,y,z){
console.log("函数的形参列表为:",arguments);
var max = -Infinity;
for(let i = 0;i < arguments.length;i++){
if (arguments[i] > max){
max = arguments[i];
}
}
console.log("形参中的最大值为:",max);
}
Print(100,250,500);
</script>
</body>
</html>
效果:
3.2参数传递引起的原始值改变
1.形参是一个值
如果传递给函数形参是一个:“值”,那么在函数中修改形参不会改变原始值的大小。
(在js中是“值传递”、和Python一样)
<script>
var x = 250;
function myVariable(x){
x = 100;
}
myVariable(x);
console.log(x);
</script>
效果:
通过“值传递”,传递给函数形参x的是一个数值,改变这个形参不会对原始的x同步修改。
2.形参是一个对象
若传递给函数形参的是一个“对象”,那么在函数内部对这个“对象”进行修改,也会对原始对象同步修改。
<script>
var x = {name:"ju"};
function myVariable(x){
x.name = "jingyi"
}
myVariable(x);
console.log(x);
</script>
效果:
可以看到原始的x也被同步修改了。
四.函数Call
4.1简介
call()方法主要用来实现“方法重用”,即在不同对象上使用的方法。
call()方法是预定义的JS方法,它可以用来调用所有者对象的属性(方法)的方法。
通俗来讲,使用call()方法,可以将“另一个对象的属性(方法)合并到本对象中”
4.2使用方法
在调用本对象方法时,附加:“.call”后缀即可。
<script>
var pig = {
name : "八戒",
weight : 250,
}
var animal = {
fullName : function () {
return this.name + "体重是:" + this.weight;
}
}
console.log(animal.fullName.call(pig));
</script>
效果;
五.函数Apply
5.1简介
apply()方法主要也是实现“方法重用”,本质上跟“call()”方法并无区别。
区别在于:
- call():call方法是一个一个接受参数
- apply():apply方法可以接受一个数组形式参数,形参分别对应数组种对应位置的元素
5.2使用方法
在本对象调用方法时,附加后缀:“.apply”即可。
<script>
var pig = {
name : "八戒",
weight : 250,
}
var animal = {
fullName : function (others) {
return this.name + "体重是:" + this.weight + "年龄是:" + others[0] + "性别是:" + others[1];
}
}
console.log(animal.fullName.call(pig,["15","女"]));
</script>
效果:
可以看到others形参对应的是数组中下标索引为0的值,也就是说只接受了数组中的一个参数。
但如果我们改成call():
<script>
var pig = {
name : "八戒",
weight : 250,
}
var animal = {
fullName : function (others) {
console.log(others);
return this.name + "体重是:" + this.weight + "年龄是:" + others[0] + "性别是:" + others[1];
}
}
console.log(animal.fullName.call(pig,["15","女"]));
</script>
效果:
可以看到数组作为一个完整的参数被传递给了“others”
六.函数绑定
6.1简介
函数绑定“bind()”用来将某个函数绑定到某个对象上,此时这个函数就成为这个对象的一个“方法”。
而如果函数中有this指针的使用,在绑定到某个的对象上之后,this指针所指就由原来的"window object"变为“对象自身”。
6.2bind的使用
bind()方法将某个函数绑定给某个对象,并且返回绑定后的新函数,并不对原对象进行修改。
此时这个函数就是“某个对象”的一个方法,在这个函数中使用this指针,代指的都是“某个对象”。
<script>
var person = {
name : "ju",
lastname : "jingyi"
}
function addition(){
return 123;
}
var newperson = addition.bind(person);
console.log(person);
console.log(newperson);
</script>
效果:
可以看到并没有对原先的person对象添加addition函数,但是此时的addition函数可以认为是person的一个对象,this指针所代指的就是person对象。
我们也可以在addition中打印this指针看看是不是person对象
<script>
var person = {
name : "ju",
lastname : "jingyi"
}
function addition(){
console.log(this);
}
var newperson = addition.bind(person);
addition();
newperson();
</script>
效果:
可以看到新的函数“newsperson”的this指针是person对象,而addition函数的this指针仍然是window对象。
七.闭包
7.1简介
闭包主要是让函数可以具备局部变量,并且这个变量不会随着函数的释放而释放。
如果学过Python或者C++等语言,可以通俗点解释,就是实现一个函数内的“静态变量”。
7.2闭包的使用
在JS中使用闭包,一般使用“嵌套函数”的形式来实现。
如果我们不使用“闭包”,我们有一个函数的作用是计时器,当调用一次这个函数,计时器的值就会加一:
<script>
var counter = 0;
function addCounter(){
counter += 1;
}
addCounter();
addCounter();
addCounter();
addCounter();
console.log(counter);
counter += 1;
console.log(counter);
</script>
效果:
可以看到,不使用闭包,我们在函数外的任何地方也可以直接对计时器进行操作,因为“计时器是一个全局变量counter”,而功能的需求是每次调用add函数才加一,在外部无法操作。
有些读者可能想到,那我每次返回counter的值不就可以了?
<script>
var counter = 0;
function addCounter(){
return counter += 1;
}
counter = addCounter();
counter = addCounter();
counter = addCounter();
console.log(counter);
</script>
这是一种可行的方法,不过若是多个线程同时对counter进行操作,很容易出现问题,且代码不容易维护,因为在函数外部仍然可以直接对counter进行修改。
那我把counter放到函数内部不可以吗?
<script>
function addCounter(){
var counter = 0;
return counter += 1;
}
counter = addCounter();
counter = addCounter();
counter = addCounter();
console.log(counter);
</script>
效果:
此时的counter作为函数内部的局部变量,当执行完一次add函数后就被释放了,所以结果自然是1
但如果聪明的读者就会想到,我可以在函数内部再嵌套一层函数不就可以了吗?
<script>
var add = (function (){
var counter = 0;
return function (){
return counter += 1;
}
})();
console.log(add());
console.log(add());
console.log(add());
</script>
效果:
同时我们无法在外部访问counter变量。