阅读 2848

JavaScript 简单/不简单 (小Tips分享)

簡單的生活從不簡單
簡單的選擇永遠知易行難

「(英)原文链接」, 我并没有一字一句的翻译,添加了一些我平时看到的知识一并分享。

如果你是一个和我一样才入门的小白,这里的分享的一些JS技巧和陷阱可以帮助你更好的学习和理解它。

如果你已经是个一言不和就开车的老司机了,那么也可以再看看,也许这里有你之前没关注到的小技巧。

1.你是否尝试过给numbers类型的数组排序❓

我们都知道, Javascript 提供了sort函数给我们使用, 那么我们来排一下

[101,2,5,100].sort()
// [ 100, 101, 2, 5 ] .复制代码

是不是和我们期待的不t太一样

The default sort order is according to string Unicode code points.

默认排序规则是数组元素 字符 的 Unicode 编码排序的,也就是说数组元素会被当做字符串,然后按照字符串的 Unicode 编码进行升序排列。

那么如果我们想按照数字的大小排序,你应该这样做

[101,2,5,100].sort((a, b) => a - b)
//[2, 5, 100, 101]复制代码

附加题(来源知乎)

给定一个List(数组), 元素都是正整数, 要求返回这些元素组成的最大数;
如[5, 2, 31, 3]则返回53312;

这里分享一下我的思路:

  • 讲数组进行排序(在地铁上想到的)
  • 怎么判断两个数的顺序的,比如31和3; 那么我们可以让它们以字符形式分别进行交叉相加,如'331' 和'313',然后根据字符大小规则进行比对
  • 然后再使用join 函数将数组组成我们要的结果

我实现的代码如下:

[5, 2, 31, 3].sort((a, b) => {
    return ('' + b + a) - ('' + a  + b)  
}).join('')复制代码

2. new Date() 非常棒👍

new Date()可以这样玩:

  • 无参调用(被当做普通函数使用):返回当前日期和时间。
    new Date()
    Wed Dec 14 2016 02:27:18 GMT+0800 (CST)复制代码
  • 一个参数(x): 返回1970-01-01加上x毫秒的时间, 熟悉Unix的朋友都知道
    new Date(1000)
    Thu Jan 01 1970 08:00:01 GMT+0800 (CST)复制代码
  • 猜一猜new(1, 1, 1)返回的是什么?
    答案是: 1901-2-01

new Date(1, 1, 1)
Fri Feb 01 1901 00:00:00 GMT+0800 (CST)复制代码
  • 第一个1,代表1901年。

    Integer value representing the year. Values from 0 to 99 map to the years 1900 to 1999

  • 第二个1,代表二月。
    是不是很奇怪,为什么是二月? (阿 二月,你比一月多一月)
    其实是这样的,月份索引也是从0开始,但是没有零月啊, 所以0代表一月,那么1就是二月咯

    Integer value representing the month, beginning with 0 for January to 11 for December.

  • 第三个1,代码月份中的第几天

于是我试了一下:

 new Date(1, 1, 29)
 Fri Mar 01 1901 00:00:00 GMT+0800 (CST)复制代码

不是说好代表一个月的第几天吗,怎么第29号没了,变成了3月1号,那我生日还过不过阿。
好吧,其实1900年的2月的确没有29号,因为1900年平年 😯
那么顺手把闰年的公式背一背吧

  • 普通年能被4整除且不能被100整除的为闰年。如2004年就是闰年,1900年不是闰年 世纪年能被400整除的是闰年。如2000年是闰年,1900年不是闰年
function isLeapYear(year) {
  return !(year % (year % 100 ? 4 : 400));
}复制代码

3. 为什么没有全部替换?

let s = "bob"
const replaced = s.replace('b', 'l')
replaced === "lob" // first match only
s === "bob" // original string is remained unchanged复制代码

我们都知道replace方法只会替换第一个,那么如果我要替换全部呢?

使用带有/ g的正则表达式:

"bob".replace(/b/g, 'l') === 'lol' // replace all occurences复制代码

有空多看看正则表达式,它还有一个外号: 瑞士军刀;

留个题目(来源DIV.io),大家可以评论答案

将ThisNimojs-JavaScript使用正则替换成 TJhaivsaNSicmroijpst

4. 相等不相等

// These are ok
'abc' === 'abc' // true
1 === 1         // true

// These are not
[1,2,3] === [1,2,3] // false
{a: 1} === {a: 1}   // false
{} === {}           // false复制代码

原因:[1,2,3]和[1,2,3]是两个单独的数组。 它们恰好包含相同的值。 它们是不同的引用;

这里我相信大部分人都是理解的;

主要是基本类型的比较和引用类型的比较的不同;

我们再看多看一个东西: ==

[10] ==  10      // 为 true
[10] === 10      // 为 false

'10' ==  10      // 为 true
'10' === 10      // 为 false

 []  ==  0       // 为 true
 []  === 0       // 为 false

 ''  ==  false   // 为 true 但 true == "a" 为false
 ''  === false   // 为 false复制代码

== (或者 !=) 操作在需要的情况下自动进行了类型转换(隐式强制转换)。=== (或 !==)操作不会执行任何转换

隐式强制转换的规则(来源justjavac):

  • 当 JavaScript 需要一个布尔值时(例如:if 语句),隐式转换为布尔:“truthy”和“falsy”
    下面的值被转换为 false:
    • undefined, null
    • Boolean: false
    • Number: -0, +0, NaN
    • String: ‘’
  • 对象的隐式转换
    只有在 JavaScript 表达式或语句中需要用到数字或字符串时,对象才被隐式转换。 当需要将对象转换成数字时,需要以下三个步骤:
    • 调用 valueOf()。如果结果是原始值(不是一个对象),则将其转换为一个数字。
    • 调用 toString() 方法。如果结果是原始值,则将其转换为一个数字。
    • 否则,抛出一个类型错误。
  • 字符串的隐式转换
    • 加运算符+ 因为只要其中一个操作数是字符串,那么它就执行连接字符串的操作(而不是加法操作,即使它们是数字)

5.Array 的类型?

typeof {} === 'object'  // true
typeof 'a' === 'string' // true
typeof 1 === number     // true
// But....
typeof [] === 'object'  // true复制代码

原作者提供了使用Array.isArray()方法用来检测数组类型

这里多提供几种

 const arr = ['l', 'o', 'v', 'e']

 // instanceof
 arr instanceof Array

 // constructor
 arr.constructor === Array

 // Object.prototype.toString
 Object.prototype.toString.call(o) === '[object Array]'

 // 结合兼容性和稳定性的最终版本

function isArray(arr){
  return Array.isArray ? Array.isArray(arr) : Object.prototype.toString.call(arr) === "[object Array]"
}复制代码

6. 又是你! 😪 闭包

先看个🌰:

const Greeters = []
for (var i = 0 ; i < 10 ; i++) {
  Greeters.push(function () { return console.log(i) })
}

Greeters[0]() // 10
Greeters[1]() // 10
Greeters[2]() // 10复制代码

期望输出的1, 2, 3没了,全都变成了10;

这里有俩个解决方案

  • 使用ES6提供的let, 关于let的技巧可以看ES2015相关的介绍,这里不啰嗦了
  • 使用bind方法
    Greeters.push(console.log.bind(null, i))复制代码

当然,还可以使用IIFE的方式,不过这俩种是原作者最喜欢的方式;

7. 细说bind

你觉得这个🌰会输出什么?

class Foo {
  constructor (name) {
    this.name = name
  }

  greet () {
    console.log('hello, this is ', this.name)
  }

  someThingAsync () {
    return Promise.resolve()
  }

  asyncGreet () {
    this.someThingAsync()
    .then(this.greet)
  }
}

new Foo('dog').asyncGreet()复制代码

答案是: Cannot read property 'name' of undefined

原因是greet的上下文环境并非dog;

现在我这样做:

asyncGreet () {
  this.someThingAsync()
  .then(this.greet.bind(this))
}复制代码

这样就确保拥有正确的上下文环境了

当然,你也可以这样做

class Foo {
  constructor (name) {
    this.name = name
    this.greet = this.greet.bind(this)
  }
}复制代码

...好像React的中这种绑定很常见(译者说的)

如果你熟悉ES2015,那么你不会忘了它=>, 箭头函数

asyncGreet () {
  this.someThingAsync()
  .then(() => {
    this.greet()
  })
}复制代码

也许有些地方翻译的不恰当,也许有些观点可能因为我的知识还不够丰富导致了错误,大家可以指出,我马上修改。 谢谢大家的观看;

关注下面的标签,发现更多相似文章
评论