【前端丛林】JavaScript这样服用,效果更佳(3)
前言
哈喽大家好,我是Lotzinfly,一位前端小猎人。欢迎大家来到前端丛林,在这里你将会遇到各种各样的前端猎物,我希望可以把这些前端猎物统统拿下,嚼碎了服用,并成为自己身上的骨肉。今天是我们冒险的第三天,经过两天的考验相信大家已经有了足够的经验,那么今天我们会遇到什么样的猎物呢?话不多说,现在开启我们今天的前端丛林冒险之旅吧!
1. var和let
- JS中作用域有:全局作用域、函数作用域。没有块作用域的概念。ECMAScript 6(简称ES6)中新增了块级作用域
- 块作用域由 { } 包括, if 语句和 for 语句里面的 { } 也属于块作用域
1.1 ES5问题
1.1.1 全局变量
- 在if或者for循环中声明的变量会变成全局变量
for(var i=0;i<=5;i++){
console.log("hello");
}
console.log(i); //5
1.1.2 内层变量可能会覆盖外层变量
var a = 1;
function fn() {
console.log(a);
if (false) {
var a = 2;
}
}
fn(); //undefined
1.2 let
- 允许块级作用域任意嵌套
- 外层作用域无法读取内层作用域的变量
- 内层作用域可以定义外层作用域的同名变量
- 函数本身的作用域在其所在的块级作用域之内
'use strict'
function fn() {
console.log("out");
}
(function () {
if (false) {
function fn() {
console.log("in");
}
}
fn();
}());
1.3 var&let&const
- var定义的变量没有块的概念,可以跨块访问,不能跨函数访问,有变量提升,可重复声明
- let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升,不可以重复声明
- let 声明的变量只在块级作用域内有效,不存在变量提升,而是绑定在暂时性死区
- 或者说let变量提升了,但是在let声明变量前不能使用该变量,这特性叫暂时性死区(temporaldead zone)
- 如果有重复变量 let 会在编译阶段报错
1.3.1 暂时性死区
// 不存在变量提升
'use strict';
function func(){
console.log(i);
let i;
};
func(); // 报错
1.3.2 全局变量
- ES5声明变量只有两种方式:var和function
- ES6有let、const、import、class再加上ES5的var、function共有六种声明变量的方式
- 浏览器环境中顶层对象是window,Node中是global对象
- ES5中 顶层对象的属性等价于全局变量
- ES6中var、function声明的全局变量,依然是顶层对象的属性;let、const、class声明的全局变量不属于顶层对象的属性
2. this
- 当前函数的this是在被调用的时候才能确定的
- 如果当前的执行上下文处于调用栈的栈顶,这个时候变量对象变成了活动对象,THIS指针才能确定
2.1 全局对象
- 全局对象this指向本身
var a=1;//声明绑定变量对象,但在全局环境中,变量对象就是全局对象
this.b=2;//this绑定全局对象
c=3;//赋值操作 隐式绑定
2.1 用点调用
- 在一个函数上下文中,this由函数的调用者提供,由调用函数的方式来决定指向
- 如果是函数执行,如果前面有点,那么点前面是谁 this 就是谁
let obj = {
getName(){
console.log(this);
}
};
obj.getName();
2.2 直接调用
- 如果没有,this就是window(严格模式下是undefined),自执行函数中的this一般都是window
let obj = {
getName(){
console.log(this);
}
};
let getName = obj.getName;
getName();
2.3 绑定事件
- 给元素绑定事件的时候,绑定的方法中的this一般是元素本身
container.addEventListener('click',function(){
console.log(this);
});
2.4 箭头函数
- 箭头函数没有自己的this
- 也没有prototype
- 也没有arguments
- 无法创建箭头函数的实例
let fn = () => {
console.log(this);
console.log(arguments);//Uncaught ReferenceError: arguments is not defined
}
console.log(fn.prototype);//undefined
fn();
new fn();//VM4416:8 Uncaught TypeError: fn is not a constructor
2.5 构造函数
- 构造函数中的THIS是当前类的实例
function fn(){}
let obj = new fn();
2.6 call/apply/bind
- call/apply/bind可以改变函数中this的指向
- 第一个参数是改变this指向(非严格模式下,传递null/undefined指向也是window)
- call参数是依次传递,apply是以数组的方式传递
!function (proto) {
function getContext(context) {
context = context || window;
var type = typeof context;
if (['number', 'string', 'boolean', 'null'].includes(type)) {
context = new context.constructor(context);
}
return context;
}
function call(context, ...args) {
context = getContext(context);
context._fn = this;
let result = context._fn(...args);
delete context._fn;
return result;
}
function apply(context, args) {
context = getContext(context);
context._fn = this;
let result = context._fn(...args);
delete context._fn;
return result;
}
function bind(context, ...bindArgs) {
return (...args) => this.call(context, ...bindArgs, ...args);
}
proto.call = call;
proto.apply = apply;
proto.bind = bind;
}(Function.prototype)
2.7绑定
- 默认绑定
- 隐式绑定
- 显式绑定
- new绑定
- new > 显式 > 隐式 > 默认
隐式 > 默认
function one() {
console.log(this)
}
var obj = {
name: "obj",
one
}
obj.one()
显式 > 隐式
function one() {
console.log(this)
}
var obj = {
name: "obj",
one: one.bind("hello")
}
obj.one()
new > 显式
function one() {
console.log(this)
}
var helloOne = one.bind("hello")
var obj = new helloOne();
console.log(obj);
结尾
好啦,这期的前端丛林大冒险先到这里啦!这期的猎物比较好对付,相信大家都可以拿下。希望大家可以好好品尝并消化,迅速升级,接下来我们将面对一个重量级猎物,大家要做好准备,我们下期再见。拜拜!
转载自:https://juejin.cn/post/7133990151897743374