尼采般地抒情

公告栏

此网站主题为本人手写主题, 主题待开源···

站点信息

文章总数目: 305
已运行时间: 1063
目录
  1. 函数定义及使用
    1. function关键字
    2. 匿名函数表达式
    3. 构造函数
    4. 立即调用函数
  2. 函数参数
    1. arguments
    2. 箭头函数(ES6)里面的不同
    3. 关于值传递
  3. 简单/复杂数据类型传参
    1. 堆栈存储区别
    2. 简单类型传参
    3. 复杂数据类型传参
  4. 几个常用 this 指向
  5. 改变函数内部 this 指向
    1. call 方法
    2. apply 方法
    3. bind 方法
    4. call、apply、bind 三者的异同
  6. 利用 setTimeout 和 setInterval 来看箭头函数中的 this
    1. 将目标对象的 this 存为一个变量
    2. 利用 bind()方法
    3. ES6 的箭头函数
  7. 如何准确判断 this 指向的是什么?(转自前端小姐姐)
  8. 闭包的作用
  9. 闭包的案例

尼采般地抒情

尼采般地抒情

公告栏

此网站主题为本人手写主题, 主题待开源···

站点信息

文章总数目: 305
已运行时间: 1063

前言:基本上和之前学过的语言一样,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(){}())

与立即执行函数相关的知识还有在函数前面加上一些符号(!、~、+……)会对函数的返回值进行相应的操作,其中加上~的意思是对返回值进行按位取反的操作,具体参考下面的参考资料

参考:https://blog.csdn.net/hot_cool/article/details/77567166


函数参数

arguments

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

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

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

es6 的箭头函数用起来很方便,但是一个不方便的就是在这里面arguments 不能用了

如果非要用的化,将这个箭头函数放在一个普通函数里面,让箭头函数接受这个普通函数的参数

关于值传递

简单/复杂数据类型传参

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

堆栈存储区别

堆栈空间分配区别:

1、栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;

简单数据类型存放到栈里面

2、堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。

简单数据类型的存储方式:值类型变量的数据直接存放在变量(栈空间)中

复杂数据类型的存储方式:引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中

简单类型传参

函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量。

function fn(a) {
a++;
console.log(a);
}
var x = 10;
fn(x);
console.log(x);

运行结果如下:

复杂数据类型传参

函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。

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. 这个输出什么 ?

运行结果如下:

二、this

几个常用 this 指向

  • 全局作用域或者普通函数中 this 指向全局对象 window(定时器里面的 this 指向 window)
function fn() {
console.log(this); // Window
}
window.fn();
window.setTimeout(function () {
console.log(this); // Window
}, 1000);
  • 方法调用中谁调用 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 这个按钮对象
});

  • 构造函数中 this 指向构造函数的实例
function Fun() {
console.log(this); // this 指向的是 fun 实例对象
}
var fun = new Fun();

改变函数内部 this 指向

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

一般指向我们的调用者.

call 方法

call()方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的 this 指向

应用场景: 经常做继承.

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 指向。

应用场景: 经常跟数组有关系

var o = {
name: 'andy'
}
function fn(a, b) {
console.log(this);
console.log(a+b)
};
fn(1, 2)// 此时的 this 指向的是 window 运行结果为 3
fn.apply(o,[1,2])//此时的 this 指向的是对象 o,参数使用数组传递 运行结果为 3

bind 方法

bind() 方法不会调用函数,但是能改变函数内部 this 指向,返回的是原函数改变 this 之后产生的新函数

如果只是想改变 this 指向,并且不想调用这个函数的时候,可以使用 bind

应用场景:不调用函数,但是还想改变 this 指向

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 指向.

利用 setTimeout 和 setInterval 来看箭头函数中的 this

在 setTimeOut()或 setInterval()这样的方法中,如果传入的函数包含 this, 那么,默认情况下,函数中的 this 会指向 window 对象。这是由于 setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致这些代码中包含的 this 关键字会指向 window (或全局)对象。有以下几种方式可以正确 this 指向:

将目标对象的 this 存为一个变量

定时器内部的函数来访问到这个变量,此时的 this,就指向了当前对象

function doClick(){
var that = this;
setInterval(function() {
console.log(that.msg);
}, 1000);
}

利用 bind()方法

function doClick(){
setInterval(function() {
console.log(this.msg);
}.bind(this), 1000); //利用 bind()将 this 绑定到这个函数上
}

ES6 的箭头函数

ES6 中的箭头函数, this 总是指向词法作用域,也就是外层调用者 obj,因此利用箭头函数就可以轻松解决这个问题

function doClick(){
setInterval(() => {
console.log(this.msg);
}, 100);
},

如何准确判断 this 指向的是什么?(转自前端小姐姐)

  1. 函数是否在 new 中调用 (new 绑定),如果是,那么 this 绑定的是新创建的对象。
  2. 函数是否通过 call,apply 调用,或者使用了 bind(即硬绑定),如果是,那么 this 绑定的就是指定的对象。
  3. 函数是否在某个上下文对象中调用 (隐式绑定),如果是的话,this 绑定的是那个上下文对象。一般是 obj.foo()。
  4. 如果以上都不是,那么使用默认绑定。如果在严格模式下,则绑定到 undefined,否则绑定到全局对象。
  5. 如果把 Null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
  6. 如果是箭头函数,箭头函数的 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()())



评论区

Twikoo giscus