web前端小白面试题(变量类型,原型链,作用域,闭包,异步,正则表达式,Math)

知识点一:变量的类型和计算

变量类型

JS变量最基本的分类就是值类型引用类型,两者有何区别呢,可以通过例子看出来。

以下是值类型的一个例子

var a = 100
var b = a
a = 200
console.log(b)

以下是引用类型的一个例子

var a = {age:20}
var b = a
b.age = 21
console.log(a.age)

typeof可以知道一个值类型是什么类型,而对于引用类型,它就无能为力了。但是它可以将引用类型区分出function,为什么 ———— 因为function相对于其他引用类型(如对象、数组)来说,具有非常特殊的意义,JS 中的函数非常重要,接下来的原型、作用域都会深入讲解函数。

JS 中的某些表现,就已经体现了函数的特殊意义,例如:对象和数组,JS中没有内置的(不考虑 JS-WEB-API),而函数却内置了很多,例如 Object Array Boolean Number String Function Date RegExp Error。这些函数 JS 本身就有,要是没有它们,就没法愉快的写 JS 代码了。因为他们是基础数据类型的构造函数(后面会讲解)

typeof可以区分类型有number string boolean undefined(值类型) function object(引用类型)

// 特例
typeof null // object 因为 null 也是引用类型。null 就相当于引用类型中的 undefined

那么针对第二个例子,如何将a的内容复制给b,并且保证b的修改不会影响到a呢?那就需要深度复制,意思就是对a的属性进行递归遍历,再依次复制,这块我们会放在后面专门讲解。

变量计算

组简单的计算,就是数字的加减乘除、字符串的拼接和替换,这个太简单了,这里不提了。但是 JS 在值类型的运算过程中,特别需要注意和利用强制类型转换这一特性,有以下场景:

  • 字符串拼接
  • ==
  • 逻辑运算(if ! || &&

字符串拼接最常见的错误如下,特别要注意。如何规避呢 ———— 对进行计算的变量通过typeof来判断类型 ———— 太麻烦?编码本身就是一个体力活!

var a = 100 + 10   // 110
var b = 100 + '10' // '10010'

接下来,==也会进行强制类型转换,如

100 == '100'   // true
0 == ''  // true
null == undefined  // true

针对100 == '100'就是和拼接字符串一样的类型转换,而针对下面两个例子,就是一个逻辑运算上的强制类型转换(马上会讲解)。所以,要求你写 JS 代码时,所有的地方都要使用===而不能使用==,但是阅读 jquery 源码后我发现一个特例,就是obj.a == null,使用很简洁。

最后,逻辑运算中的强制类型转换,先以if为例说明

var a = true
if (a) {
    // ....
}
var b = 100
if (b) {
    // ....
}
var c = ''
if (c) {
    // ....
}

所有经过if判断的变量,都会进行逻辑运算的强制类型转换,转换为true或者false

console.log(10 && 0)  // 0
console.log('' || 'abc')  // 'abc'
console.log(!window.abc)  // true

// 判断一个变量会被当做 true 还是 false
var a = 100
console.log(!!a)

日常开发中,以下变量会被转换为false

  • 0
  • NaN (NaN用来表示最终结果并非数字。)
  • ‘’
  • null
  • undefined
  • false 本身

除了以上几个,其他的都会被转换为true除了if之外,! || &&这三个运算符也会进行同样的转换,跟if是一个道理。因此,如何快速判断一个变量将会被if转换为什么呢?————!!a

答题

JS中使用typeof能得到的哪些类型

针对这个题目,可以通过以下程序进行验证

typeof undefined // undefined
typeof 'abc' // string
typeof 123 // number
typeof true // boolean
typeof {}  // object
typeof [] // object
typeof null // object
typeof console.log // function

何时使用=== 何时使用==

首先你得明白两者的区别。==会先试图类型转换,然后再比较,而===不会类型转换,直接比较。如下例子:

1 == '1' // true
1 === '1' // false
0 == false // true
0 === false // false
null == undefined // true
null === undefined // false

根据 jQuery 源码中的写法,只推荐在一个地方用==,其他地方都必须用===。这个用==的地方就是:

if (obj.a == null) {  // 这里相当于 obj.a === null || obj.a === undefined ,简写形式
}

编程是需要绝对严谨的态度,我们只在这一个地方让它进行类型转换,来简化我们的写法,因为这个场景非常简单和固定。而其他场景下,我们都必须使用===,除非有特殊的业务需要。

JS中有哪些内置函数 —— 数据封装类对象

Object Array Boolean Number String Function Date RegExp Error

JS变量按照存储方式区分为哪些类型,并描述其特点

  • 值类型 undefined string number boolean
  • 引用类型 object function

最后补充一点,在 JS 中,所有的引用类型都可以自由设置属性

var obj = {}
obj.a = 100

var arr = []
arr.a = 100

function fn() {}
fn.a = 100

如何理解JSON

这个问题,很容易被一些初学者误答。其实,JSON 是什么?从 JS 角度回答,太简单了,console.log(JSON)得到JSON只是一个对象,有parsestringify两个方法,使用也非常简单

JSON.stringify({a:10, b:20})
JOSN.parse('{"a":10,"b":20}')

知识点二:原型和原型链

JS 是基于原型的语言,原型理解起来非常简单。任何长存不会被遗弃和提到的东西,都是最简单的东西。

构造函数

所有的 JS 入门教程都会有类似这样的例子

function Foo(name, age) {
    this.name = name
    this.age = age
    this.class = 'class-1'
    // return this  // 默认有这一行
}
var f = new Foo('zhangsan', 20)
// var f1 = new Foo('lisi', 22)  // 创建多个对象

以上示例是通过new Foo创建出来一个f对象,对象有name age class三个属性,这样我们就称Foof构造函数。构造函数这个概念在高级语言中都存在,它就像一个模板一样,可以创建出若干个示例。

函数执行的时候,如果前面带有new,那么函数内部的this在执行时就完全不一样了,不带new的情况我们下一章节会讲到。带new执行时,函数中的this就会变成一个空对象,让程序为其属性赋值,然后最终返回。return this是默认执行的,如何验证?———— 你可以最后加一个return {x:10}试一下。返回之后,f就被赋值成了这个新对象,这样就创建完成了。

构造函数 - 扩展

  • var a = {}其实是var a = new Object()的语法糖
  • var a = []其实是var a = new Array()的语法糖
  • function Foo(){...}其实是var Foo = new Function(...)的语法糖

大家看到以上几点,明白我要表达的意思了吗?

如何判断一个函数是否是一个变量的构造函数呢 ———— 使用instanceof,原理接下来就会讲到。

几个要点

  • 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了null意外)
  • 所有的引用类型(数组、对象、函数),都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
  • 所有的函数,都有一个prototype属性,属性值也是一个普通的对象
  • 所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的prototype属性值
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn () {}
fn.a = 100;

console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);

console.log(fn.prototype)

console.log(obj.__proto__ === Object.prototype)

原型

我们先将一开始的示例做一下改动,然后看一下执行的效果

// 构造函数
function Foo(name, age) {
    this.name = name
}
Foo.prototype.alertName = function () {
    alert(this.name)
}
// 创建示例
var f = new Foo('zhangsan')
f.printName = function () {
    console.log(this.name)
}
// 测试
f.printName()
f.alertName()

执行printName时很好理解,但是执行alertName时发生了什么?这里再记住一个重点 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找

那么如何判断一个这个属性是不是对象本身的属性呢?使用hasOwnProperty,常用的地方是遍历一个对象的时候

var item
for (item in f) {
    // 高级浏览器已经在 for in 中屏蔽了来自原型的属性,但是这里建议大家还是加上这个判断,保证程序的健壮性
    if (f.hasOwnProperty(item)) {
        console.log(item)
    }
}

原型链

还是接着上面的示例,执行f.toString()时,又发生了什么?因为f本身没有toString(),并且f.__proto__(即Foo.prototype)中也没有toString。这个问题还是得拿出刚才那句话————当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找

如果在f.__proto__中没有找到toString,那么就继续去f.__proto__.__proto__中寻找,因为f.__proto__就是一个普通的对象而已嘛!

这样一直往上找,你会发现是一个链式的结构,所以叫做“原型链”。直到找到最上层都没有找到,那么就宣告失败,返回undefined。最上层是什么 ———— Object.prototype.__proto__ === null

原型链中的this

所有的从原型或者更高级的原型中得到、执行的方法,其中的this在执行时,就指向了当前这个触发事件执行的对象。因此printNamealertName中的this都是f

instanceof

开始介绍的instanceof这里再讲一下原理。如果要计算f instanceof Foo是不是正确,就要判断f的原型一层一层往上,能否对应到Foo.prototype。同理,如果要计算f instanceof Object是不是正确,就要判断f的原型一层一层往上,能否对应到Object.prototype

知识点三:作用域和闭包

执行上下文

先看下面的例子,你可能会对结果比较差异。当然,我不建议在实际开发中通过这种方式来炫技,我们这里演示纯粹是为了讲解知识点做一个铺垫。

console.log(a)  // undefined
var a = 100

fn('zhangsan')  // 'zhangsan' 20
function fn(name) {
    age = 20
    console.log(name, age)
    var age
}

在一段 JS 脚本(即一个<script>标签中)执行之前,会先创建一个全局执行上下文环境,先把代码中即将执行的(内部函数的不算,因为你不知道函数何时执行)变量、函数声明(和“函数表达式”的区别)都拿出来。变量先暂时赋值为undefined,函数则先声明好可使用。这一步做完了,然后再开始正式执行程序。再次强调,这是在代码执行之前才开始的工作。

另外,一个函数在执行之前,也会创建一个函数执行上下文环境,跟全局上下文差不多,不过函数执行上线文中会多出this arguments和函数的参数。参数和arguments好理解,这里的this咱们需要专门讲解。

总结一下

  • 范围:一段<script>或者一个函数
  • 全局:变量定义,函数声明
  • 函数:变量定义,函数声明,this,arguments

this

先搞明白一个很重要的概念 ———— this的值是在执行的时候才能确认,定义的时候不能确认! 为什么呢 ———— 因为this是执行上下文环境的一部分,而执行上下文需要在代码执行之前确定,而不是定义的时候。看如下例子

var a = {
    name: 'A',
    fn: function () {
        console.log(this.name)
    }
}
a.fn()  // this === a
a.fn.call({name: 'B'})  // this === {name: 'B'}
var fn1 = a.fn
fn1()  // this === window

this执行会有不同,主要集中在这几个场景中

  • 作为构造函数执行

  • 作为对象属性执行

  • 作为普通函数执行

  • 用于call apply bind

  • 1.构造函数
    function Foo(name){
    //var this = {}
    this.name=name
    //return this
    }
    var f = new Foo('zhangsan)

  • 2.对象属性
    var obj = {
    name:‘A’,
    printName:function(){
    console.log(this.name)
    }
    }
    obj.printName()

  • 3.普通函数执行
    function fn(){
    console.log(this)
    }
    fn() //window

  • 4.call apply bind
    function fn1(name,age){
    console.log(name)
    console.log(this)
    }
    fn1.call({x:100},‘zhangsan’,20)
    fn1.apply({x:100},[‘zhangsan’,20])

var fn2 = function(name,age){
console.log(name)
console.log(this)
}.bind({y:300})
fn2.(‘zhangsan’,300)

前两种情况咱们之前都介绍过了,这里只是统一的提出来,汇总一下,不再详细讲了。这里主要说第三种

function fn() {
    console.log(this)
}
fn()  // window
fn.call({a:100})  // {a:100}  和 call 同理的还有 apply bind

作用域

自由变量
作用域链,(自由变量的查找)
闭包的两个场景

作为有 JS 基础的同学,你应该了解 JS 没有块级作用域。例如

if (true) {
    var name = 'zhangsan'
}
console.log(name)

从上面的例子可以体会到作用域的概念,作用域就是一个独立的地盘,让变量不会外泄、暴露出去。上面的name就被暴露出去了,因此,JS 没有块级作用域,只有全局作用域和函数作用域

var a = 100
function fn() {
    var a = 200
    console.log('fn', a)
}
console.log('global', a)
fn()

全局作用域就是最外层的作用域,如果我们写了很多行 JS 代码,变量定义都没有用函数包括,那么他们就全部都在全局作用域中。这样的坏处就是很容易装车。

// 张三写的代码中
var data = {a:100}

// 李四写的代码中
var data = {x:true}

这就是为何 jquery zepto 等库的源码,所有的代码都会放在(function(){....})()中。因为放在里面的所有变量,都不会被外泄和暴露,不会污染到外面,不会对其他的库或者 JS 脚本造成影响。这是函数作用域的一个体现。

作用域链

首先认识一下什么叫做自由变量。如下代码中,console.log(a)要得到a变量,但是在当前的作用域中没有定义a(可对比一下b)。当前作用域没有定义的变量,这成为自由变量。自由变量如何得到 ———— 向父级作用域寻找。

var a = 100
function fn() {
    var b = 200
    console.log(a)
    console.log(b)
}
fn()

如果父级也没呢?再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是作用域链

var a = 100
function F1() {
    var b = 200
    function F2() {
        var c = 300
        console.log(a)
        console.log(b)
        console.log(c)
    }
    F2()
}
F1()

闭包

直接看一个例子

function F1() {
    var a = 100
    return function () {
        console.log(a)  //a是自由变量  函数 -  定义的时候的父作用域
    }
}
var f1 = F1()
var a = 200
f1()     //100

自由变量将从作用域链中去寻找,但是依据的是函数定义时的作用域链,而不是函数执行时,以上这个例子就是闭包。闭包主要有两个应用场景:

  • 函数作为返回值,上面的例子就是
  • 函数作为参数传递,看以下例子
function F1() {
    var a = 100  //还是来这里寻找 
    return function () {
        console.log(a)
    }
}
function F2(f1) {
    var a = 200
    console.log(f1())
}
var f1 = F1()
F2(f1)  //100

解题

说一下对变量提升的理解

函数执行时会先创建当前的上下文环境,其中这两点会产生“变量提升”的效果

  • 变量定义
  • 函数声明

说明 this 几种不同的使用场景

  • 作为函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • call apply bind

创建 10 个<a>标签,点击的时候弹出来对应的序号

错误的写法

var i, a
for (i = 0; i < 10; i++) {
    a = document.createElement('a')
    a.innerHTML = i + '<br>'
    a.addEventListener('click', function (e) {
        e.preventDefault()
        alert(i)  //自由变量要去父级作用域取值  父作用域就是全局作用域
    })
    document.body.appendChild(a)
}

正确的写法

自执行的函数,就是不用调用,定义完成立即执行 的函数

var i
for (i = 0; i < 10; i++) {
    (function (i) {
        var a = document.createElement('a')
        a.innerHTML = i + '<br>'
        a.addEventListener('click', function (e) {
            e.preventDefault()
            alert(i)
        })
        document.body.appendChild(a)
    })(i)
}

上面的回答已经结束了,但是还有一点可以优化,如果能做到,那将会给你加分。提示一下,是关于 DOM 操作的性能问题的。这里先按下不表,等后面讲解性能问题的时候再说。有兴趣的可以先去查查DocumentFragment

实际开发中闭包的应用

闭包的实际应用,主要是用来封装变量,收敛权限。即把变量隐藏起来,不让外面拿到和修改。

function isFirstLoad() {
    var _list = []

    return function (id) {
        if (_list.indexOf(id) >= 0) {// 说明:有重复的  如果要检索的字符串值没有出现,则该方法返回 -1。
            return false
        } else {
            _list.push(id)
            return true
        }
    }
}

// 使用
var firstLoad = isFirstLoad()
firstLoad(10) // true
firstLoad(10) // false
firstLoad(20) // true
var i;                                                  //声明变量
for(i=0;i<10;i++){                                      //循环
    (function(i){                                       //自执行的函数,就是不用调用,定义完成立即执行 的函数
    //函数作用于
        var a = document.createElement('button');       //创建标签
        a.innerHTML = i+'<br />';                       //html显示内容
        a.addEventListener('click',function(e){         //添加事件
        e.preventDefault();                             //取消时间的默认动作
        alert(i);                                       //自由变量要去父作用域取值
    })
    document.body.appendChild(a)                        //添加到body里面
})(i)

}

知识点四:异步

什么是异步

先看下面的 demo,根据程序阅读起来表达的意思,应该是先打印100,1秒钟之后打印200,最后打印300。但是实际运营根本不是那么回事。

console.log(100)
setTimeout(function () {
    console.log(200)
}, 1000)
console.log(300)

再对比以下程序。先打印100,再弹出200(等待用户确认),最后打印300。这个运行效果就符合预期要求。

console.log(100)
alert(200)  // 1秒钟之后点击确认
console.log(300)

这俩到底有何区别?———— 第一个示例中间的步骤根本没有阻塞接下来程序的运行,而第二个示例却阻塞了后面程序的运行。前面这种表现就叫做异步(后面这个叫做同步

为何需要异步呢?如果第一个示例中间步骤是一个 ajax 请求,现在网络比较慢,请求需要5秒钟。如果是同步,这5秒钟页面就卡死在这里啥也干不了了。

最后,前端 JS 脚本用到异步的场景主要有两个:

  • 定时 setTimeout setInverval
  • 网络请求,如 ajax <img>加载
  • 事件绑定(后面会有解释)click等

ajax 代码示例

console.log('start')
$.get('./data1.json', function (data1) {
    console.log(data1)
})
console.log('end')

img 代码示例(常用语打点统计)

console.log('start')
var img = document.createElement('img')
img.onload = function () {
    console.log('loaded')
}
img.src = '/xxx.png'
console.log('end')

事件绑定

console.log('start')
document.getElementById('btn1').addEventListener('click', function () {
    alert('clicked')
})
console.log('end')

异步和单线程

JS 在客户端运行的时候,只有一个线程可运行,因此想要两件事儿同时干是不可能的。如果没有异步,我们只能同步干,就像第二个示例一样,等待过程中卡住了,但是有了异步就没有问题了。那么单线程是如何实现异步的呢?

console.log(100)
setTimeout(function () {
    console.log(200)
})
console.log(300)

那上面的示例来说,有以下几点。重点从这个过程中体会单线程这个概念,即事情都是一步一步做的,不能两件事儿一起做。

  • 执行第一行,打印100
  • 执行setTimeout后,传入setTimeout的函数会被暂存起来,不会立即执行。
  • 执行最后一行,打印300
  • 待所有程序执行完,处于空闲状态时,会立马看有没有暂存起来的要执行。
  • 发现暂存起来的setTimeout中的函数无需等待时间,就立即来过来执行

下面再来一个setTimeout的例子。规则和上面的一样,只不过这里暂存起来的函数,需要等待 1s 之后才能被执行。

console.log(100)
setTimeout(function () {
    console.log(200)
}, 1000)
console.log(300)

下面再来一个 ajax 的例子。规则也是一样的,只不过这里暂存起来的函数,要等待网络请求返回之后才能被执行,具体时间不一定。

console.log(100)
$.get('./data.json', function (data) {
    console.log(200)
})
console.log(300)

最后再解释一下事件绑定,如下代码。其实事件绑定的实现原理和上面的是一样的,也是会把时间暂存,但是要等待用户点击只有,才能被执行。原理是一样的,因此事件绑定在原理上来说,可以算作是异步。但是从设计上来说,还是分开好理解一些。

console.log(100)
$btn.click(function () {
    console.log(200)
})
console.log(300)

重点:异步的实现机制,以及对单线程的理解


下面的暂时先不讲

异步的问题和解决方案

异步遇到的最大的问题

  • callback-hell
  • 易读性差,即书写顺序和执行顺序不一致
console.log('start')
$.get('./data1.json', function (data1) {
    console.log(data1)
    $.get('./data2.json', function (data2) {
        console.log(data2)
        $.get('./data3.json', function (data3) {
            console.log(data3)
            $.get('./data4.json', function (data4) {
                console.log(data4)
                // ...继续嵌套...
            })
        })
    })
})
console.log('end')

解答

同步和异步的区别是什么?分别举一个同步和异步的例子

同步会阻塞代码执行,而异步不会。alert是同步,setTimeout是异步

一个关于setTimeout的笔试题

面试题中,setTimeout的基本是必会出现的

// 以下代码执行后,打印出来的结果是什么
console.log(1)
setTimeout(function () {
    console.log(2)
}, 0)
console.log(3)
setTimeout(function () {
    console.log(4)
}, 1000)
console.log(5)

该题目的答案是1 3 5 2 4,不知道跟你答对了没有。具体的原理,我们后面再详细讲解。

前端使用异步的场景有哪些

  • setTimeout setInterval
  • 网络请求
  • 事件绑定(可以说一下自己的理解)

知识点五:其他基础知识

正则表达式

test函数的用法

var ua = navigator.userAgent
var reg = /\bMicroMessenger\b/i
console.log(reg.test(ua))

用于replace的示例

function trim(str) {
    return str.replace(/(^\s+)|(\s+$)/g, '')
}

match函数的用法

var url = 'http://www.abc.com/path/xxx.html?a=10&b=20&c=30#topic'  // 后面的 #topic 也可能没有
var reg = /\?(.+?)(#|$)/
var matchResult = url.match(reg)
console.log(matchResult[1]) // a=10&b=20&c=30

略过正则表达式,不讲


日期函数

日期函数最常用的 API 如下

Date.now()  // 获取当前时间毫秒数
var dt = new Date()
dt.getTime()  // 获取毫秒数
dt.getFullYear()  // 年
dt.getMonth()  // 月(0 - 11)
dt.getDate()  // 日(0 - 31)
dt.getHours()  // 小时(0 - 23)
dt.getMinutes()  // 分钟(0 - 59)
dt.getSeconds()  // 秒(0 - 59)

Math

Math 最常用的只有一个 API —— Math.random()

数组常用 API

  • forEach
  • every
  • some
  • sort
  • map
  • filter

forEach 举例

var arr = [1,2,3]
arr.forEach(function (item, index) {
    // 遍历数组的所有元素
    console.log(index, item)
})

every 举例

var arr = [1,2,3]
var result = arr.every(function (item, index) {
    // 用来判断所有的数组元素,都满足一个条件
    if (item < 4) {
        return ture
    }
})
console.log(result)

some 举例

var arr = [1,2,3]
var result = arr.some(function (item, index) {
    // 用来判断所有的数组元素,只要有一个满足条件即可
    if (item < 2) {
        return ture
    }
})
console.log(result)

sort 举例

var arr = [1,4,2,3,5]
var arr2 = arr.sort(function(a, b) {
    // 从小到大排序
    return a - b
    // 从大到小排序
    // return b - a
})
console.log(arr2)

map 举例

var arr = [1,2,3,4]
var arr2 = arr.map(function(item, index) {
    // 将元素重新组装,并返回
    return '<b>' + item + '</b>'
})
console.log(arr2)

filter 举例

var arr = [1,2,3]
var arr2 = arr.filter(function (item, index) {
    // 通过某一个条件过滤数组
    if (item >= 2) {
        return true
    }
})
console.log(arr2)

对象常用 API

  • for-in
在看开源项目的过程中,经常会看到类似如下的源码。for...in循环对象的所有枚举属性,然后再使用hasOwnProperty()方法来忽略继承属性。
var obj = {
    x: 100,
    y: 200,
    z: 300
}
var key
for (key in obj) {
    // 注意这里的 hasOwnProperty,再讲原型链时候讲过了
    if (obj.hasOwnProperty(key)) {
        console.log(key, obj[key])
    }
}

解答

获取2017-06-10格式的日期

function formatDate(dt) {
    if (!dt) {
        dt = new Date()
    }
    var year = dt.getFullYear()
    var month = dt.getMonth() + 1
    var date = dt.getDate()
    if (month < 10) {
        // 强制类型转换
        month = '0' + month
    }
    if (date < 10) {
        // 强制类型转换
        date = '0' + date
    }
    // 强制类型转换
    return year + '-' + month + '-' + date
}
var dt = new Date()
var formatDate = formatDate(dt)
console.log(formatDate)

获取随机数,要求是长度一直的字符串格式

使用Math.random()可获取字符串,但是返回的是一个小于 1 的小数,而且小数点后面长度不同

var random = Math.random()
var random = random + '0000000000'  // 后面加上 10 个零
var random = random.slice(0, 10)
console.log(random)

写一个能遍历对象和数组的forEach函数

遍历数组使用forEach,而遍历对象使用for in,但是在实际开发中,可以使用一个函数就遍历两者,jquery 就有这样的函数

function forEach(obj, fn) {
    var key
    if (obj instanceof Array) {
        // 准确判断是不是数组
        obj.forEach(function (item, index) {
            fn(index, item)
        })
    } else {
        // 不是数组就是对象
        for (key in obj) {
            fn(key, obj[key])
        }
    }
}

var arr = [1,2,3]
// 注意,这里参数的顺序换了,为了和对象的遍历格式一致
forEach(arr, function (index, item) {
    console.log(index, item)
})

var obj = {x: 100, y: 200}
forEach(obj, function (key, value) {
    console.log(key, value)
})

//遍历
var arr = [1,23,31,13];
arr.forEach(function(item,index){
console.log(index,item)
})

//所有的值都满足
var arr = [1,23,31,13];
var result = arr.every(function(item,index){
if(item<5){
return true
}
})
console.log(result)
//有一个值满足
var arr = [1,23,31,13];
var result = arr.some(function(item,index){
if(item<5){
return true
}
})
console.log(result)
//排序
var arr = [1,23,31,13];
var result = arr.sort(function(a,b){

    return a-b

})
console.log(result)

//嵌入标签
var arr = [1,23,31,13];
var result = arr.map(function(item,index){

    return '<b>'+item+'</b>'

})
console.log(result)
//过滤
var arr = [1,23,31,13];
var result = arr.filter(function(item,index){
if(item>2){
return true
}
})
console.log(result)

Math 是数学函数,但又属于对象数据类型 typeof Math => ‘object’
console.dir(Math) 查看Math的所有函数方法。

1,Math.abs() 获取绝对值

Math.abs(-12) = 12

2,Math.ceil() and Math.floor() 向上取整和向下取整

console.log(Math.ceil(12.03));//13
console.log(Math.ceil(12.92));//13
console.log(Math.floor(12.3));//12
console.log(Math.floor(12.9));//12

3,Math.round() 四舍五入

注意:正数时,包含5是向上取整,负数时包含5是向下取整。

1、Math.round(-16.3) = -16
2、Math.round(-16.5) = -16
3、Math.round(-16.51) = -17

4,Math.random() 取[0,1)的随机小数

案例1:获取[0,10]的随机整数

console.log(parseInt(Math.random()*10));//未包含10
console.log(parseInt(Math.random()*10+1));//包含10
案例2:获取[n,m]之间的随机整数

Math.round(Math.random()*(m-n)+n)

5,Math.max() and Max.min() 获取一组数据中的最大值和最小值

console.log(Math.max(10,1,9,100,200,45,78));
console.log(Math.min(10,1,9,100,200,45,78));

6,Math.PI 获取圆周率π 的值

console.log(Math.PI);

7,Math.pow() and Math.sqrt()

Math.pow()获取一个值的多少次幂
Math.sqrt()对数值开方

1.Math.pow(10,2) = 100;
2.Math.sqrt(100) = 10;

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值