JavaScript严格模式说明及变量函数的提升
一.严格模式的简单说明
1.函数调用的方式和this的丢失
(1)函数的调用方法:
- 001 以对象的方法来调用 this--->对象
- 002 以普通的函数的方法来调用 this--->window
- 003 以构造函数的方式来调用 new Function() this---->指内部新创建的对象
- 004 以函数上下文的方式来调用(call|apply) this--->绑定的第一个参数 如果不传递参数那么默认指向window
解决this的丢失问题:
eg:
<script>
//var getId = document.getElementById('demo');//以对象的方法来调用
/* var getId = document.getElementById;// getId代表是一个函数
console.log(getId('demo')); */ //报错 (以普通函数的方法来调用)this的丢失问题!
//document.getElementById('demo');
//getId('demo');
//原因:document.getElementById的内部实现中使用到了this,内部的this始终指向document
//以普通函数的方式来调用,内部的this指向的是window
//解决问题:
//将this绑定给document
var getId = (function (func){
return function (){
//return func.apply(document,arguments);
return func.call(document,arguments[0]);
}
})(document.getElementById);
console.log(getId('demo'));
var getTagName = (function (func){
return function (){
//return func.apply(document,arguments);
return func.call(document,arguments[0]);
}
})(document.getElementsByTagName);
console.log(getTagName('div')[0]);
</script>
2.严格模式的简单说明
严格模式:
js有两种开发模式:严格模式和非严格模式(默认)
在严格模式下:会对代码进行更严格的检查.以前在默认情况下可能不会出错或者是静默失败或者是可以使用的特性,那么会在严格模式下会直接报错.
开启严格模式:
在当前作用域的最顶端加上一个命令字符串:'use strict';
兼容性问题:
- 部分浏览器不支持严格模式.
- 如果该引擎支持严格模式,那么当检测到'use strict';这个字符串的时候会自动开启严格模式,如果不支持那么就忽略.
严格模式的使用注意:
- 01 所有的变量必须使用var声明
- 02 禁止使用with
- 03 禁止使用八进制
- 04 禁止使用callee | caller
- 05 禁止使用eval和arguments作为标识符
- 06 在if语句中不能声明函数
- 07 在函数的声明中不能出现同名的参数
- 08 在对象中不能出现同名的属性
- 09 在严格模式下arguments的表现略微的不同
- 10 不能删除全局变量
- 11 this的指向被修正
建议:使用严格模式来开发.
eg:
<script>
'use strict';
//01 所有的变量必须使用var声明
/* b = 'testB';
console.log(b);*/
//02 禁止使用with
/* var obj = {
name:'张三'
}
with(obj){
name:'李四'
}
console.log(obj);*/
//03 禁止使用八进制
//八进制说明:如果数值前面是0,那么默认以八进制的方式来处理
//如果数字中出现超过8的数字,那么以十进制的方式来处理
/* var n = 027;
console.log(n);*/
//04 禁止使用callee | caller
//callee 指向自己 用于匿名函数的递归中
//caller 指向调用者
/* function func01(){
console.log(func01.caller);
}
function func02(){
func01();
}
func02();
console.log((function (n){
if(n == 1){
return 1;
}
return arguments.callee(n-1)+n;
})(11));*/
//05 禁止使用eval和arguments作为标识符(变量|对象|函数的名称)
/* var arguments = 'demo';
console.log(arguments);
//06 在if语句中不能声明函数
if(true){
function test(){
console.log('test');
}
test();
}*/
//07 在函数中不能出现同名的参数
//默认情况下,如果函数中出现同名的形参,那么后面一个会把前面一个覆盖
/*function foo(a,b,a){
/!*var a = 1;
var b = 2;
var a = 3;*!/
console.log(a+b+c);//8
}
foo(1,2,3);*/
//08 对象中也不能出现同名的参数 (默认情况下,后面的会覆盖前面的)
/* var o = {
name:'张三',
name:'李四'
}
console.log(o.name);*/
//09 不能删除全局变量
//默认情况下删除失败,但是不会报错 (静默失败)
/* var obj = '我是测试的魔镜';
console.log(delete obj);
console.log(obj);*/
//10 argumnets在严格模式下和非严格模式下表现不一致的
//默认情况下,在函数内部重新设置形参的值,arguments也会跟着改变,他们是共享的
//严格模式下,他们是相互独立的
function demoTest(stringTest){
console.log(stringTest);//String
console.log(arguments);//
stringTest = '我是一个字符串';
console.log(stringTest);
console.log(arguments);
}
demoTest('String');
function demoTestObj(obj){
console.log(obj);
console.log(arguments);
obj = {age:23};
console.log(obj);
console.log(arguments);
}
demoTestObj({});
console.log('+++++++++++++++');
//11 修正了this的指向
//默认情况下,指向的是window
//严格模式下,指向的是undefined;
var name = 'window的name';
function func01(){
console.log(this);
}
func01();//undefined
var o = {
name:'张三',
showName:function (){
console.log(this);
}
}
o.showName();//张三
var o2 = {
name:'李四'
}
o.showName.call(null);//null
//默认情况下不传参数,那么this指向window,严格模式下指向的是undefined
// 如果传递的参数是null,那么this的值就是null
</script>
3.严格模式的书写格式
- 位置: 当前作用域的最顶端
- 书写格式:
① 双引号和单引号无所谓
② 必须全部都是小写字符
③ 分号可以被省略
④ 必须是10个字符
eg:
<script>
// "use strict";
// "use strict" //省略分号 正确
// use strict; //不加引号 错误
// 'use strict'; //单引号 正确
// "use strict"; //错误的
// "use strict "; //错误的
// "use Strict";
var a = 'testA';
b = 'testB';
</script>
4.严格模式的作用域说明
作用域:
js中的作用域分为两种:全局作用域(例如script作用域内 )和函数作用域
作用域: 变量起作用的范围
块级作用域:
- js没有块级作用域
- 注意:try...catch例外(有块级作用域)
函数作用域:
在js中只有函数可以创建作用域;
词法作用域:
- 词法作用域:当代码写好之后,它的作用域就已经确定了
- 动态作用域:作用域范围在程序运行的时候确定;
- js本身是词法作用域(with + eval + try...catch 除外);
词法作用域的访问规则:
首先先在自己的作用域中查找,如果找到那么就直接使用,如果没有找到那么就在上一级的作用域中查找,重复这个过程
eg:
<script>
var a = 'testA';
function test01(){
var a = 123;
var b = '456';
console.log(a);
function test02(){
console.log(b);
console.log(a);
}
test02();
}
test01();
console.log(a);
</script>
<script>
function hi(){
console.log('hi');
}
var hello = function hi(){
console.log('hello');
}
hello();//hello
hi();//hi //当赋值之后,就不能再直接使用名称来调用
</script>
<script>
var a = 'testA';
function add(n){
//函数作用域
}
</script>
<script>
for(var i = 0;i<10;i++) {
console.log(i);
}
console.log(i,'------------');
try{
a();
}
catch (e){
console.log(e);
}
console.log(e,'______________');//报错
</script>
eg2:
<script>
'use strict'; //位置1 作用范围是全局
function demo1(){
'use strict'; //位置2 demo1
a = 'testA';
}
function demo2(){
'use strict'; //位置3 demo2
b = 'testB';
}
'use strict'; //位置4 无效
demo1();
demo2();
</script>
二.变量和函数的提升
1. 变量和函数的提升
01 js预先解析处理 变量和函数的提升 把变量和函数提升在作用域顶端
02 具体执行
eg:
<script>
console.log(b);//报错
console.log(a);//undefined
var a = 'testA';//var a; a= 'testA';
console.log(a);//testA;
</script>
<script>
function demo(){
console.log('demo');
}
console.log(typeof demo);//function
demo();//demo
</script>
注意点:
- 01 变量和变量同名的情况, 后面的变量会把前面的同名变量覆盖
- 02 函数和函数名, 后面的函数会把前面的同名函数覆盖
- 03 变量和函数同名情况 , 前后关系无所谓
eg:
//01 变量和变量同名的情况
<script>
var num = 10;
function demo1(){
num = 20;
console.log(num);//20
demo2();//30
console.log(num);//30
}
function demo2(){
num = 30;
console.log(num);//
}
demo1();
//02函数和函数名
var a = 'testA';
console.log(a);//testA
var a = 'testB';
console.log(a);//testB
//03变量和函数同名情况
demo1();
function demo1(){
console.log('demo1')
}
demo1();
function demo1(){
console.log('demo2');
}
demo1();
//04变量和函数同名情况
var str = '我是一个字符串';
str = function (){
console.log('我的同桌是美女')
}
console.log(str);//function()...
</script>
2.变量的提升作用于不同的作用域
eg:
<script>
var num = 10;
function func(){
console.log(num);//10
num = 20;
}
console.log(num);//10
func();//10
console.log(num);//20
/* var num;
function func(){
console.log(num);//undefined
num = 20;
}
num = 10;
console.log(num);//10
func();//10
console.log(num);//20*/
</script>
3.函数表达式的提升
函数表达式: 那么在提升的时候仅仅只会把var 变量名提升
eg:
<script>
var demo;
console.log(demo);//undefined
demo();//报错
demo = function (){
console.log('11111111');
}
</script>