尼采般地抒情

公告栏

此网站主题为本人手写主题,主题还在开发中……


作者:尼采般地抒情

站点信息

文章数目:240
已运行时间:
目录
  1. 函数定义使用
    1. function 关键字
    2. 匿名函数表达式
    3. 构造函数
    4. 立即调用函数
  2. 函数参数
    1. arguments
    2. 箭头函数(ES6)里面的不同
    3. 关于值传递
  3. this
    1. 几个常用 this 指向
    2. 函数内部的 this 指向
    3. 改变函数内部 this 指向
  4. 闭包
    1. 闭包的作用
    2. 闭包的案例
  5. 简单/复杂数据类型传参
    1. 堆栈存储区别
    2. 简单类型传参
    3. 复杂数据类型传参
  6. 理解 js 里面的任务执行机制
    1. 啥是单线程
    2. 同步任务和异步任务
    3. JS 执行机制(事件循环)
    4. JS 创建异步任务枚举
    5. 期约 Promise

尼采般地抒情

尼采般地抒情

公告栏

此网站主题为本人手写主题,主题还在开发中……


作者:尼采般地抒情

站点信息

文章数目:240
已运行时间:
基本上和之前学过的语言一样,return语句、continue语句、break语句、函数的传参用法基本都一样,记录一下js的特征用法:

函数定义使用

不像之前的 C++、JAVA 那样需要一个返回值来声明,JavaScript 里面直接一个关键字就搞定了,如果里面有 return 就返回 return 的值,没有则返回 undefined。下面记录一下 js 里面的三种函数声明方式和不同情况下的使用场景。

function 关键字

自定义函数方式(命名函数)利用函数关键字 function 自定义函数方式

// 声明定义方式
function fn() {...}
// 调用
fn();
  • 调用函数的代码既可以放到声明函数的前面,也可以放在声明函数的后面

匿名函数表达式

::: > 函数表达式方式(匿名函数) > 【C++11里面也有匿名函数的用法,基本上就是**匿名函数表达式**】
// 这是函数表达式写法,匿名函数后面跟分号结束
var fn = function(){...};
// 调用的方式,函数调用必须写到函数体下面
fn();
  • 这个 fn 里面存储的是一个函数
  • 函数表达式方式原理跟声明变量方式是一致的
  • 函数调用的代码必须写到函数体后面

构造函数

  • 所有函数都是 Function 的对象,函数也是对象
var f = new Function('a', 'b', 'console.log(a + b)');
f(1, 2);
var fn = new Function('参数1','参数2'..., '函数体')

立即调用函数

两种表达方式

  • (function(){})()
  • (function(){}())

与立即执行函数相关的知识还有在函数前面加上一些符号(!、、+……)会对函数的返回值进行相应的操作,其中加上的意思是对返回值进行按位取反的操作,具体参考下面的参考资料
image.png
参考:https://blog.csdn.net/hot_cool/article/details/77567166

函数参数

arguments

image.png
当不确定有多少个参数传递的时候,可以用 arguments 来获取。JavaScript 中,arguments 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有实参。arguments 展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:

  • 具有 length 属性
  • 按索引方式储存数据
  • 不具有数组的 push , pop 等方法
    注意:在函数内部使用该对象,用此对象获取函数调用时传的实参。

箭头函数(ES6)里面的不同

es6 的箭头函数用起来很方便,但是一个不方便的就是在这里面 arguments 不能用了
image.png
如果非要用的化,将这个箭头函数放在一个普通函数里面,让箭头函数接受这个普通函数的参数
image.png

关于值传递

image.png

this

几个常用 this 指向

  • 全局作用域或者普通函数中 this 指向全局对象 window(定时器里面的 this 指向 window)
  • 方法调用中谁调用 this 指向谁
  • 构造函数中 this 指向构造函数的实例
<button>点击</button>
    <script>
        // this 指向问题 一般情况下this的最终指向的是那个调用它的对象
        // 1. 全局作用域或者普通函数中this指向全局对象window( 注意定时器里面的this指向window)
        console.log(this);
        function fn() {
            console.log(this);
        }
        window.fn();
        window.setTimeout(function() {
            console.log(this);
        }, 1000);
        // 2. 方法调用中谁调用this指向谁
        var o = {
            sayHi: function() {
                console.log(this); // this指向的是 o 这个对象
            }
        }
        o.sayHi();
        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
                console.log(this); // 事件处理函数中的this指向的是btn这个按钮对象
            })
        // 3. 构造函数中this指向构造函数的实例
        function Fun() {
            console.log(this); // this 指向的是fun 实例对象
        }
        var fun = new Fun();
    </script>

函数内部的 this 指向

这些 this 的指向,是当我们调用函数的时候确定的。调用方式的不同决定了 this 的指向不同
一般指向我们的调用者.

改变函数内部 this 指向

call方法
call()方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的 this 指向 应用场景: 经常做继承. ```js var o = { name: 'andy' } function fn(a, b) { console.log(this); console.log(a+b) }; fn(1,2)// 此时的this指向的是window 运行结果为3 fn.call(o,1,2)//此时的this指向的是对象o,参数使用逗号隔开,运行结果为3 ```
apply方法
apply() 方法调用一个函数。简单理解为调用函数的方式,但是它可以改变函数的 this 指向。 应用场景: 经常跟数组有关系 ```js var o = { name: 'andy' } function fn(a, b) { console.log(this); console.log(a+b) }; fn()// 此时的this指向的是window 运行结果为3 fn.apply(o,[1,2])//此时的this指向的是对象o,参数使用数组传递 运行结果为3 ```
bind方法
bind() 方法不会调用函数,但是能改变函数内部this 指向,返回的是原函数改变this之后产生的新函数 如果只是想改变 this 指向,并且不想调用这个函数的时候,可以使用bind 应用场景:不调用函数,但是还想改变this指向 ```js var o = { name: 'andy' }; function fn(a, b) { console.log(this); console.log(a + b); }; var f = fn.bind(o, 1, 2); //此处的f是bind返回的新函数 f();//调用新函数 this指向的是对象o 参数使用逗号隔开 ```
call、apply、bind三者的异同
  • 共同点 : 都可以改变 this 指向
  • 不同点:
    • call 和 apply 会调用函数, 并且改变函数内部 this 指向.
    • call 和 apply 传递的参数不一样,call 传递参数使用逗号隔开,apply 使用数组传递
    • bind 不会调用函数, 可以改变函数内部 this 指向.
  • 应用场景
    1. call 经常做继承.
    2. apply 经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值
    3. bind 不调用函数,但是还想改变 this 指向. 比如改变定时器内部的 this 指向.

闭包

闭包(closure)指有权访问另一个函数作用域中变量的函数。简单理解就是 ,一个作用域可以访问另外一个函数内部的局部变量。

闭包的作用

作用:延伸变量的作用范围。

function fn() {
  var num = 10;
  function fun() {
    console.log(num);
  }
  return fun;
}
var f = fn();
f();

闭包的案例

  1. 利用闭包的方式得到当前 li 的索引号
for (var i = 0; i < lis.length; i++) {
  // 利用for循环创建了4个立即执行函数
  // 立即执行函数也成为小闭包因为立即执行函数里面的任何一个函数都可以使用它的i这变量
  (function (i) {
    lis[i].onclick = function () {
      console.log(i);
    };
  })(i);
}
  1. 闭包应用-3 秒钟之后,打印所有 li 元素的内容
for (var i = 0; i < lis.length; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(lis[i].innerHTML);
    }, 3000);
  })(i);
}
  1. 闭包应用-计算打车价格
/*需求分析
打车起步价13(3公里内),  之后每多一公里增加 5块钱.  用户输入公里数就可以计算打车价格
如果有拥堵情况,总价格多收取10块钱拥堵费*/
var car = (function () {
  var start = 13; // 起步价  局部变量
  var total = 0; // 总价  局部变量
  return {
    // 正常的总价
    price: function (n) {
      if (n <= 3) {
        total = start;
      } else {
        total = start + (n - 3) * 5;
      }
      return total;
    },
    // 拥堵之后的费用
    yd: function (flag) {
      return flag ? total + 10 : total;
    },
  };
})();
console.log(car.price(5)); // 23
console.log(car.yd(true)); // 33
var name = "The Window";
   var object = {
     name: "My Object",
     getNameFunc: function() {
     return function() {
     return this.name;
     };
   }
 };
console.log(object.getNameFunc()())
-----------------------------------------------------------------------------------
var name = "The Window";  
  var object = {    
    name: "My Object",
    getNameFunc: function() {
    var that = this;
    return function() {
    return that.name;
    };
  }
};
console.log(object.getNameFunc()())

简单/复杂数据类型传参

**简单类型**(**基本数据类型**、**值类型**):在存储时变量中存储的是值本身,包括string ,number,boolean,undefined,null
**复杂数据类型(引用类型)**:在存储时变量中存储的仅仅是地址(引用),通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等;

堆栈存储区别

堆栈空间分配区别:
1、栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;
简单数据类型存放到栈里面
2、堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。
image.png
简单数据类型的存储方式:值类型变量的数据直接存放在变量(栈空间)中
image.png
复杂数据类型的存储方式:引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中
image.png

简单类型传参

函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量。
function fn(a) {
    a++;
    console.log(a);
}
var x = 10;
fn(x);
console.log(x);
    运行结果如下:

image.png

复杂数据类型传参

函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
function Person(name) {
    this.name = name;
}
function f1(x) { // x = p
    console.log(x.name); // 2. 这个输出什么 ?
    x.name = "张学友";
    console.log(x.name); // 3. 这个输出什么 ?
}
var p = new Person("刘德华");
console.log(p.name);    // 1. 这个输出什么 ?
f1(p);
console.log(p.name);    // 4. 这个输出什么 ?
    运行结果如下:

image.png

理解 js 里面的任务执行机制

相关概念

  • 异步编程
  • Javascript 的事件循环
  • 任务队列
  • 微任务队列
  • ……

以下代码执行的结果是什么?

console.log(1);

setTimeout(function () {
  console.log(3);
}, 3000);

console.log(2);

image.png
以下代码执行的结果是什么?

console.log(1);

setTimeout(function () {
  console.log(3);
}, 0);

console.log(2);

image.png

啥是单线程


单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

同步任务和异步任务

单线程导致的问题就是后面的任务等待前面任务完成,如果前面任务很耗时(比如读取网络数据),后面任务不得不一直等待!!
为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制。于是,JS 中出现了**同步任务**和**异步任务**。

操作系统忘完了

JS 中所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。
【同步任务】指的是:
在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
【异步任务】指的是:
不进入主线程、而进入“任务队列”的任务,当主线程中的任务运行完了,才会从”任务队列”取出异步任务放入主线程执行。

JS 执行机制(事件循环)



例子

console.log("主线程:第一个");
document.onclick = function () {
  console.log("点击事件开始");
};
setTimeout(function () {
  console.log("定时器3s");
}, 3000);
setTimeout(function () {
  console.log("定时器1s");
}, 1000);
console.log("主线程:最后一个");

image.png
image.png

JS 创建异步任务枚举

参考:

期约 Promise

博客内容遵循: 署名-非商业性使用-禁止演绎 4.0 国际(CC BY-NC-ND 4.0)

本文永久链接: https://www.wztlink1013.com/blog/egols2d1kxs2/

编辑: 部署: 订阅:

评论区

Twikoo 转换 utterances