javaScirpt学习第五章(函数)-第二部分
本次函数内容比较多,我们分了两不分。
- window 对象
- this 指向等问题
1、windows对象
Window对象
- 在浏览器中,浏览器为我们提供了一个window对象,可以直接访问
window对象代表的是浏览器窗口,通过该对象可以对浏览器窗口进行各种操作
除此之外window对象还负责存储JS中的内置对象和浏览器的宿主对象- window对象的属性可以通过window对象访问,也可以直接访问
函数就可以认为是window对象的方法
- window对象的属性可以通过window对象访问,也可以直接访问
var 用来声明变量,作用和let相同,但是var不具有块作用域
- 在全局中使用var声明的变量,都会作为window对象的属性保存
- 使用function声明的函数,都会作为window的方法保存
- 使用let声明的变量不会存储在window对象中,而存在一个秘密的小地方(无法访问)
- var虽然没有块作用域,但有函数作用域
- 使用function声明的函数,都会作为window的方法保存
示例使用
当我们调用alert,console,confirm,xxx 时候,我们有没有想过,这些函数我们自己也没有定义,他们是怎么来的呢,其实在浏览器内部,有一个window对象负责管理这些所有的函数,包含默认的已经自定义的函数,都由这个统一管理
alert
alert(window);// object window
window.xx 使用
当我们声明了一个 var a = 10,实际上就是 window.a = 10 这种赋值操作;
- 向window对象中添加的属性会自动成为全局变量
window.a = 10;
console.log(a);// 10
声明函数使用window对象
function fn() {
alert(‘我是函数fn’);
}window.fn();
注意点
function fn2 () {
// var d = 22;//var虽然没有块作用域,但有函数作用域
d = 88;// 在局部作用域中,如果没有使用var或let声明变量,则变量会自动成为window对象的属性 也就是全局变量
}
fn2();//
console.log(d)//88
2、let和var以及函数执行顺序
变量的提升
使用var声明的变量,它会在所有代码执行前被声明
- 所以我们可以在变量声明前就访问变量
函数的提升
使用函数声明创建的函数,会在其他代码执行前被创建
- 所以我们可以在函数声明前调用函数
let声明的变量实际也会提升,但是在赋值之前解释器禁止对该变量的访问
变量提升
console.log(b);
var b = 10;// 在下面申明 undefined
//let b = 10;// 在下面申明 Cannot access ‘b’ before initialization
函数提升
fn();//我是fn函数方法-----》》》
//函数提升
function fn() {
console.log(‘我是fn函数方法-----》》》’)
}
对变量未声明
//var a = 10;
a = 10;// window.a = 10
3、小练习
<script>
var a = 1;
function fn() {
a = 2;
console.log(a);//2
}
fn();
console.log(a);//2
// 变量和函数的提升同样适用于函数作用域
var a1 = 1;
function fn1() {
console.log("fn1-->",a1);//undefined
var a1 = 2;
console.log("fn1-->",a1);//2
}
fn1();
console.log("a1-->",a1);//1
// 定义形参就相当于在函数中声明了对应的变量,但是没有赋值
var a2 = 22;
function fn2(a2) {
console.log("fn2-->",a2);//undefined
a2 = 33;
console.log("fn2-->",a2);//33
}
fn2();
console.log("a2-->",a2);//22
// 案例3
var a3 = 33;
function fn3(a3) {
console.log('fn3-->',a3);//33
a3 = 19;
console.log('fn3-->',a3);// 19
}
fn3(a3);
console.log('a3-->',a3);//19
// 案例4
var a4 = 4;
console.log('a4--->',a4);//4
// 函数名字叫 a4
function a4() {
alert('fn--->a4')
}
console.log('a4--->',a4);//4
var a4 = 41;
console.log('a4--->',a4);//41
var a4 = function() {
alert('fn--->a4->')
}
console.log('a4--->',a4);//函数内容
var a4;
console.log('a4--->',a4);//函数内容
</script>
4、debug 使用
debug就是用来调试程序,停留在某一段地方,让代码一行一行的执行,让我们看到程序的变化使用。
第一种使用方式
打开浏览器的F12 快捷键
第二种方式
debugger // 在代码中打了一个断点这个时候代码就停留在这里了;
5、立即执行函数
立即执行函数(IIFE)
立即是一个匿名的函数,并它只会调用一次
可以利用IIFE来创建一个一次性的函数作用域,避免变量冲突的问题
注意
在开发中应该尽量减少直接在全局作用域中编写代码!
所以我们的代码要尽量编写的局部作用域
如果使用let声明的变量,可以使用{}来创建块作用域
示例使用
<script>
// 使用let 申明变量 不使用var
{
let a = 10;
}
{
let a = 20;
}
//console.log(a);//a is not defined
// 函数里面写var 这种有自己的作用域
function fn1() {
var b = 10;
}
fn1();
//console.log('b==>',b);// b is not defined
// 希望可以创建一个只执行一次的匿名函数
(function() {
let c = 10;
console.log('c==>',c);//c==> 10
}());
// 注意,如果我们需要写两个函数,一定记得要在函数结束后面加上分号
// ,或者加上其他逻辑,避免连接到一起而不能解析
//方式2 括号写到外面
(function() {
let c = 10;
console.log('c==>',c);//c==> 10
}) ()
</script>
6、this
- 函数在执行时,JS解析器每次都会传递进一个隐含的参数
这个参数就叫做 this- this会指向一个对象
- this所指向的对象会根据函数调用方式的不同而不同
1.以函数形式调用时,this指向的是window
2.以方法的形式调用时,this指向的是调用方法的对象
…
- 通过this可以在方法中引用调用方法的对象
示例使用
<script>
function fn() {
console.log(this === window);// true
console.log('fn对象是什么',this)// Window
}
fn();// window 对象
window.fn();// 如上
// 对象调用
const obj1 = {name: '孙悟空'};
obj1.test = fn;
obj1.test();// {name: '孙悟空', test: ƒ}
const obj2 = {name: '猪八戒',test: fn}
obj2.test();//{name: '猪八戒', test: ƒ} this 取谁调用,调用的对象是谁
const obj3 = {
name: '唐僧',
sayHello: function () {
console.log(this.name)
}
}
const obj4 = {
name: '唐僧1',
sayHello: function () {
console.log(this.name)
}
}
obj3.sayHello();//唐僧
obj4.sayHello();//唐僧唐僧1
</script>
7、箭头函数
箭头函数:
([参数]) => 返回值
例子:
无参箭头函数:() => 返回值
一个参数的:a => 返回值
多个参数的:(a, b) => 返回值
只有一个语句的函数:() => 返回值
只返回一个对象的函数:() => ({…})
有多行语句的函数:() => {
…
return 返回值
}
箭头函数没有自己的this,它的this有外层作用域决定
箭头函数的this和它的调用方式无关
示例使用
<script>
// 普通函数this
function fn1() {
console.log('fn1---->',this)
}
const fn2 = () => {
console.log('fn2--->',this)
}
fn1();//Window
fn2();//Window
const obj = {
name: '孙悟空',
fn1,//fn1:fn1
fn2,
sayHello() {
console.log(this.name)
function t() {
console.log('t--->',this)
}
t();//Window
const t2 = () => {
console.log('t2--->',this);
}
t2();// 指向的是对象
}
}
obj.fn1();// obj对象
obj.fn2();// window 对象
obj.sayHello();
// 总结,箭头函数的this是,谁调用我,那么我得this就是谁
// 其他函数的this 不定,箭头函数的指向比较稳定
</script>
8、严格模式
JS运行代码的模式有两种:
正常模式
- 默认情况下代码都运行在正常模式中,
在正常模式,语法检查并不严格
它的原则是:能不报错的地方尽量不报错 - 这种处理方式导致代码的运行性能较差
- 默认情况下代码都运行在正常模式中,
严格模式
- 在严格模式下,语法检查变得严格
1.禁止一些语法
2.更容易报错
3.提升了性能
- 在严格模式下,语法检查变得严格
在开发中,应该尽量使用严格模式,
这样可以将一些隐藏的问题消灭在萌芽阶段,
同时也能提升代码的运行性能
实例使用
<script>
"use strict"//全局的严格模式
let a = 10
console.log(a)
// b = 11;//b is not defined
// console.log(b)
// 函数里面使用严格模式
function fn() {
'use strict'
//c = '123'//: c is not defined
}
fn()
</script>