美文网首页
JS的深入浅出

JS的深入浅出

作者: JLong | 来源:发表于2020-01-09 09:00 被阅读0次


隐式转换

隐式转换 数据类型 +-巧用 a==b a===b(严格等于)

包装对象

原始类型是没有对象属性的,但是类似a.t或者a.length等操作,会转换成一个临时对象,但是当返回后,临时对象被销毁,所以alert(a.t)为undefined

类似上面

类型检测

typeof

typeof返回字符串,判断基本类型,函数对象非常方便,对其他对象不怎方便

instanceof Object.prototype.toString

instanceof判断对象类型,基于原型链判断;typeof返回字符串,通常用于原始类型以及函数对象,如判断一个东西是不是原始类型或者函数,用typeof比较合适。

var a=b=1;  a被创建为局部/全局(看位置)变量,b被创建为全局变量

函数声明与函数表达式

区别:函数前置,函数声明会被预先处理,可在其前面调用函数,函数表达式则不行。

obj.hasOwnProperty('z'); //true   检测obj上是否存在z属性(判断自身属性是否存在)

!注意:用for in遍历属性有可能会把原型链上的属性也遍历出来,但是顺序是不确定的

hasOwnProperty() //判断对象是否存在属性,同时可用来过滤掉原型链上的属性(巧用)     propertyIsEnumerable() //判断对象是否可枚举

!!注意:defineProperty定义属性默认等于false;巧用&&可以用来判断属性是否存在;!=一般等于空,undefined等于null

sort按字母大小排序

arr.sort(function(a,b){

    return a - b 

});

slice():索引切片,左闭右开区间,负数索引表示从后往前,对原数组进行修改

arr.forEach(function(a,index,n){

})

a:值,index:索引,n:true/false

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

reduceRight()方法的功能和reduce()功能是一样的,不同的是reduceRight()从数组的末尾向前将数组中的数组项做累加。

第一个参数:查找的元素;第二个参数:开始查找的位置

函数:

函数声明可声明前置,函数表达式不可以

不常见,a、b:形参,第三个:字符串代码,存在安全隐患

this



闭包:


闭包的作用:结合实际案例:

https://blog.csdn.net/u011086209/article/details/88858277

作用域:

在javascript中,是没有块级作用域这种说法的


匿名函数(自执行)

匿名函数顾名思义指的是没有名字的函数,在实际开发中使用的频率非常高!也是学好JS的重点。

匿名函数:没有实际名字的函数。

首先我们声明一个普通函数:

//声明一个普通函数,函数的名字叫fn

function fn(){

    console.log("张培跃");

}

然后将函数的名字去掉即是匿名函数:

//匿名函数,咦,运行时,你会发现报错啦!

function (){

    console.log("张培跃");

}

到此,你会发现单独运行一个匿名函数,由于不符合语法要求,报错啦!解决方法只需要给匿名函数包裹一个括号即可:

//匿名函数在其它应用场景括号可以省略

(function (){

    //由于没有执行该匿名函数,所以不会执行匿名函数体内的语句。

    console.log("张培跃");

})

如果需要执行匿名函数,在匿名函数后面加上一个括号即可立即执行!

(function (){

    //此时会输出张培跃

    console.log("张培跃");

})()

倘若需要传值,直接将参数写到括号内即可:

(function (str){

    //此时会输出张培跃好帅!

    console.log("张培跃"+str);

})("好帅!")

匿名函数的应用场景

1、事件

<input type="button" value="点我啊!" id="sub">

<script>

    //获得按钮元素

    var sub=document.querySelector("#sub");

    //给按钮增加点击事件。

    sub.onclick=function(){

        alert("当点击按钮时会执行到我哦!");

    }

</script>

2、对象

var obj={

    name:"张培跃",

    age:18,

    fn:function(){

        return "我叫"+this.name+"今年"+this.age+"岁了!";

    }

};

console.log(obj.fn());//我叫张培跃今年18岁了!

3、函数表达式

//将匿名函数赋值给变量fn。

var fn=function(){

    return "我是一只小小小小留下,怎么飞也飞不高!"

}

//调用方式与调用普通函数一样

console.log(fn());//我是一只小小小小留下,怎么飞也飞不高!

4、回调函数

setInterval(function(){

    console.log("我其实是一个回调函数,每次1秒钟会被执行一次");

},1000);

5、返回值

//将匿名函数作为返回值

function fn(){

    //返回匿名函数

    return function(){

        return "张培跃";

    }

}

//调用匿名函数

console.log(fn()());//张培跃

//或

var box=fn();

console.log(box());//张培跃

模仿块级作用域

块级作用域,有的地方称为私有作用域。JavaScript中是没有块级作用域的,例如:

if(1==1){//条件成立,执行if代码块语句。

    var a=12;//a为全局变量

}

console.log(a);//12

for(var i=0;i<3;i++){

    console.log(i);

}

console.log(i);//4

if(){}for(){}等没有自己的作用域。如果有,出了自己的作用域,声明的变量就会立即被销毁了。但是咱们可以通过匿名函数来模拟块级作用域:

(function(){

    //这里是我们的块级作用域(私有作用域)

})();

尝试块级作用域:

function fn(){

    (function(){

        var la="啦啦啦!";

    })();

    console.log(la);//报错---la is not defined

}

fn();


匿名函数的作用:

1、通过匿名函数可以实现闭包,关于闭包在后面的文章中会重点讲解。在这里简单介绍一下:闭包是可以访问在函数作用域内定义的变量的函数。若要创建一个闭包,往往都需要用到匿名函数。

2、模拟块级作用域,减少全局变量。执行完匿名函数,存储在内存中相对应的变量会被销毁,从而节省内存。再者,在大型多人开发的项目中,使用块级作用域,会大大降低命名冲突的问题,从而避免产生灾难性的后果。自此开发者再也不必担心搞乱全局作用域了。

执行上下文:

OOP

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。

用于继承Person.prototype,避免对Person.prototype造成污染

bind函数没有prototype属性

hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。

继承:

第一种不可以,会污染Person.prototype属性

js继承的6种方式

想要继承,就必须要提供个父类(继承谁,提供继承的属性)

一、原型链继承

重点:让新实例的原型等于父类的实例。

特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)

缺点:1、新实例无法向父类构造函数传参。

2、继承单一。

3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)

二、借用构造函数继承

重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))

特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。

2、解决了原型链继承缺点1、2、3。

3、可以继承多个构造函数属性(call多个)。

4、在子实例中可向父实例传参。

缺点:1、只能继承父类构造函数的属性。

2、无法实现构造函数的复用。(每次用每次都要重新调用)

3、每个新实例都有父类构造函数的副本,臃肿。

三、组合继承(组合原型链继承和借用构造函数继承)(常用)

重点:结合了两种模式的优点,传参和复用

特点:1、可以继承父类原型上的属性,可以传参,可复用。

2、每个新实例引入的构造函数属性是私有的。

缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。

四、原型式继承

重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。

特点:类似于复制一个对象,用函数来包装。

缺点:1、所有实例都会继承原型上的属性。

2、无法实现复用。(新实例属性都是后面添加的)

五、寄生式继承

重点:就是给原型式继承外面套了个壳子。

优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。

缺点:没用到原型,无法复用。

六、寄生组合式继承(常用)

寄生:在函数内返回对象然后调用

组合:1、函数的原型等于另一个实例。2、在函数中用apply或者call引入另一个构造函数,可传参

重点:修复了组合继承的问题

继承这些知识点与其说是对象的继承,更像是函数的功能用法,如何用函数做到复用,组合,这些和使用继承的思考是一样的。上述几个继承的方法都可以手动修复他们的缺点,但就是多了这个手动修复就变成了另一种继承模式。

这些继承模式的学习重点是学它们的思想,不然你会在coding书本上的例子的时候,会觉得明明可以直接继承为什么还要搞这么麻烦。就像原型式继承它用函数复制了内部对象的一个副本,这样不仅可以继承内部对象的属性,还能把函数(对象,来源内部对象的返回)随意调用,给它们添加属性,改个参数就可以改变原型对象,而这些新增的属性也不会相互影响。

Javascript是弱类型,不想java,没有绝对的机制去实现参数重载,因为函数不确定,传入个数可以任意。

正则表达式:

垃圾回收机制

垃圾回收

JavaScript 中的内存管理是自动执行的,而且是不可见的。我们创建基本类型、对象、函数……所有这些都需要内存。

当不再需要某样东西时会发生什么? JavaScript 引擎是如何发现并清理它?

可达性

JavaScript 中内存管理的主要概念是可达性。

简单地说,“可达性” 值就是那些以某种方式可访问或可用的值,它们被保证存储在内存中。

1. 有一组基本的固有可达值,由于显而易见的原因无法删除。例如:

本地函数的局部变量和参数

当前嵌套调用链上的其他函数的变量和参数

全局变量

还有一些其他的,内部的

这些值称为根。

2. 如果引用或引用链可以从根访问任何其他值,则认为该值是可访问的。

例如,如果局部变量中有对象,并且该对象具有引用另一个对象的属性,则该对象被视为可达性, 它引用的那些也是可以访问的,详细的例子如下。

JavaScript 引擎中有一个后台进程称为垃圾回收器,它监视所有对象,并删除那些不可访问的对象。

一个简单的例子

下面是最简单的例子:

这里箭头表示一个对象引用。全局变量“user”引用对象 {name:“John”} (为了简洁起见,我们将其命名为John)。John 的 “name” 属性存储一个基本类型,因此它被绘制在对象中。

如果 user 的值被覆盖,则引用丢失:

现在 John 变成不可达的状态,没有办法访问它,没有对它的引用。垃圾回收器将丢弃 John 数据并释放内存。

两个引用

现在让我们假设我们将引用从 user 复制到 admin:

现在如果我们做同样的事情:

该对象仍然可以通过 admin 全局变量访问,所以它在内存中。如果我们也覆盖admin,那么它可以被释放。

相互关联的对象

现在来看一个更复杂的例子, family 对象:

函数 marry 通过给两个对象彼此提供引用来“联姻”它们,并返回一个包含两个对象的新对象。

到目前为止,所有对象都是可访问的。

现在让我们删除两个引用:

仅仅删除这两个引用中的一个是不够的,因为所有对象仍然是可访问的。

但是如果我们把这两个都删除,那么我们可以看到 John 不再有传入的引用:

输出引用无关紧要。只有传入的对象才能使对象可访问,因此,John 现在是不可访问的,并将从内存中删除所有不可访问的数据。

无法访问的数据块

有可能整个相互连接的对象变得不可访问并从内存中删除。

源对象与上面的相同。然后:

这个例子说明了可达性的概念是多么重要。

很明显,John和Ann仍然链接在一起,都有传入的引用。但这还不够。

“family”对象已经从根上断开了链接,不再有对它的引用,因此下面的整个块变得不可到达,并将被删除。

内部算法

基本的垃圾回收算法称为“标记-清除”,定期执行以下“垃圾回收”步骤:

垃圾回收器获取根并“标记”(记住)它们。

然后它访问并“标记”所有来自它们的引用。

然后它访问标记的对象并标记它们的引用。所有被访问的对象都被记住,以便以后不再访问同一个对象两次。

以此类推,直到有未访问的引用(可以从根访问)为止。

除标记的对象外,所有对象都被删除。

例如,对象结构如下:

我们可以清楚地看到右边有一个“不可到达的块”。现在让我们看看“标记并清除”垃圾回收器如何处理它。

现在进程中不能访问的对象被认为是不可访问的,将被删除:

这就是垃圾收集的工作原理。JavaScript引擎应用了许多优化,使其运行得更快,并且不影响执行。

一些优化:

分代回收——对象分为两组:“新对象”和“旧对象”。许多对象出现,完成它们的工作并迅速结 ,它们很快就会被清理干净。那些活得足够久的对象,会变“老”,并且很少接受检查。

增量回收——如果有很多对象,并且我们试图一次遍历并标记整个对象集,那么可能会花费一些时间,并在执行中会有一定的延迟。因此,引擎试图将垃圾回收分解为多个部分。然后,各个部分分别执行。这需要额外的标记来跟踪变化,这样有很多微小的延迟,而不是很大的延迟。

空闲时间收集——垃圾回收器只在 CPU 空闲时运行,以减少对执行的可能影响。


面试怎么回答

1)问什么是垃圾

一般来说没有被引用的对象就是垃圾,就是要被清除, 有个例外如果几个对象引用形成一个环,互相引用,但根访问不到它们,这几个对象也是垃圾,也要被清除。

2)如何检垃圾

一种算法是 标记-清除 算法,另一种是引用计数(主要用在IE游览器)

call()、apply()

apply方法能劫持另外一个对象的方法,继承另外一个对象的属性

Function.apply(obj,args)方法能接收两个参数,第一个参数是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是数组,也可以是arguments对象

obj:这个对象将代替Function类里this对象

args:这个是数组,它将作为参数传给Function(args–>arguments)

学生类里没有给name和age属性赋值啊,为什么又存在这两个属性的值呢,这个就是apply的神奇之处。

分析:Person.apply(this,arguments);

this:代表的是student,表示将Person中的this指向student。

arguments:是一个数组,在例子中表示[‘A','10','一年级'];

通俗一点讲就是:用student去执行Person这个类里面的内容,在Person这个类里面存在this.name等之类的语句,这样就讲属性创建到了student对象里面.

apply()和call()的作用是一样的,他们的区别仅在于接收参数的方式不同,call()需要把参数一个个列出来。

call()的用法

在Student函数里面可以将apply中修改成如下:

3.什么情况下用apply(),什么情况下用call()

至于是使用apply()还是call(),取决于采取那种给函数传递参数的方式最方便。

如果打算直接传入arguments对象,或者是数组,并且参数列表相同则使用apply();否则,选择call()可能更合适。

例:apply示例里面传递了参数arguments,并且在调用Person的时候参数的列表是对应一致的,也就是Person和Student的参数列表前两位是一致的,就可以采用apply。

如果我的Person的参数列表是这样的(age,name)而Student的参数列表是(name,age,grade),这样的就可以用call来实现了Person.call(this,age,name,grade);

相关文章

  • js基础--this详解

    最近在imooc看深入浅出js,上机实践,做了一些笔记和心得。 今天还是在复习js基础,把imooc深入浅出js的...

  • JavaScript深入浅出第3课:什么是垃圾回收算法?

    摘要: JS是如何回收内存的? 《JavaScript深入浅出》系列: JavaScript深入浅出第1课:箭头函...

  • 2021-04-07each和foreach

    深入浅出 Node.js(三):深入 Node.js 的模块机制 https://www.infoq.cn/art...

  • Node.js 有什么弊端

    《深入浅出 Node.js》阅读随笔 此文为《为什么选择 Node.js》姊妹篇,简单聊一下 Node.js 的缺...

  • 2018 第一本书

    阿啦嘞:《深入浅出nodejs》《JS promise迷你书》 不折腾:[ √ ] 《王小波系列》 llp:《皮...

  • 《深入浅出 Vue.js》书评

    本书信息: ISBN:9787115509055 豆瓣读书:《深入浅出 Vue.js》[https://book....

  • 异步编程的困惑

    《深入浅出 Node.js》阅读随笔 众所周知,Node.js 虽然也有部分同步编程的方式,但主要还是以后异步编程...

  • 发现•分享—2019-01-25

    工具 深入浅出webpack baidu-search-optimization 文章 JS 前端缓存最佳实践 C...

  • Node.js 有必要写测试用例吗?

    《深入浅出 Node.js》阅读随笔 先说结论:很有必要!不单是 Node.js,除非是作为体验或者 Demo 演...

  • 发布/订阅模式

    《深入浅出 Node.js》阅读随笔 Node.js 下使用发布/订阅的模式写程序,可以很优雅的解藕业务逻辑,尤其...

网友评论

      本文标题:JS的深入浅出

      本文链接:https://www.haomeiwen.com/subject/tqqobctx.html