资讯专栏INFORMATION COLUMN

JS基础之常用小技巧和知识总结(一)

dadong / 984人阅读

摘要:如果有一方是布尔值,则转换为,转换为,再进行判断。等同运算符类型不同返回类型相同如果同为数字字符串则比较值如果同为布尔值,相同则为不同为如果两个操作数同为引用类型,且引用的为同一个对象函数,数组,则相同。

</>复制代码

  1. 本文主要记录平时开发遇到的知识点和小技巧

相等判断(==)

类型相同: 判断其值是否相同

类型不同:

</>复制代码

  1. 1. 如果数字和字符串比较, 则字符串会被隐式转换为数字,在做判断。
  2. 2. 如果有一方是布尔值, 则true 转换为 1false 转换为 0 ,再进行判断。
  3. 3. 如果其中有一个值为对象, 则对象会调取自身的valueOf 或者toString方法进行转换,再做判断。
  4. 4.undefinednull 相等。
等同运算符(===)

</>复制代码

  1. 类型不同: 返回false
  2. 类型相同:
  3. 1. 如果同为数字/字符串, 则比较值
  4. 2. 如果同为布尔值, 相同则为true, 不同为false
  5. 3. 如果两个操作数同为引用类型,且引用的为同一个对象(函数,数组),则相同。

所以使用 === 进行逻辑判断的时候,自己就要很清楚两边的数据类型。 比如调用函数得到的是字符串"1", 与 数字 1 比较的时候,得到的false, 不要犯类似的低级错误。

this指针

</>复制代码

  1. javascript中, this表示当前上下文, 即调用者的引用。

</>复制代码

  1. var tom = {
  2. sex: "M",
  3. age: 20
  4. }
  5. var jerry = {
  6. sex: "F",
  7. age: 18
  8. }
  9. function getAge() {
  10. return this.age;
  11. }
  12. console.log(getAge.call(tom)); // 20
  13. console.log(getAge.call(jerry)); // 18
  14. // 通过call 方法, 改变了getAge函数中this的指向, this不会指向getAge函数本身。
  15. var person = {
  16. first: "john",
  17. last: "tom",
  18. getFull: function () {
  19. console.log(this.first + " " + this.last);
  20. }
  21. }
  22. person.getFull(); // john tom
  23. //this 指向person
  24. var firstName = "will";
  25. var lastName = "smith";
  26. function getFull() {
  27. console.log(this.firstName + " " + this.lastName);
  28. }
  29. getFull(); // will smith
  30. //调用者是window,所以 this 指向window
  31. function a() {
  32. console.log(this);
  33. }
  34. a.call(null);

</>复制代码

  1. call 调用一个对象的一个方法,以另一个对象替换当前对象。

  2. 格式如 call(thisObj, arg1,arg2...argN);

  3. 在函数体外部调用call()方法,如果传入null,则默认转成window,如果不传也是一样,即函数中的this指向window
    console.log(this) // window;

</>复制代码

  1. function a() {
  2. console.log(this === window);
  3. }
  4. console.log(this === window); // true
  5. a.call(); // true
  6. a.call(null); // true
  7. a.call(this); // true
  8. a.call(window); // true
  9. a(); // true

</>复制代码

  1. this 的值并非取决于如何被定义, 而是取决于调用方式
    更多有关函数调用的内容请翻阅javascript语言精粹第四章的函数部分。
    更多有关this的内容可以翻阅《你不知道的javascript上卷》第二章。

变量声明与函数声明提升

</>复制代码

  1. JavaScript会将所有变量和函数声明移动到它的作用域的最前面,这就是所谓的变量提升(Hoisting)。

也就是说,无论你在什么地方声明变量和函数,解释器都会将它们移动到作用域的最前面。因此我们可以先使用变量和函数,而后声明它们.

但是,仅仅是变量声明被提升了,而变量赋值不会被提升。

如果你不明白这一点,有时则会出错:

</>复制代码

  1. console.log(a); // 输出undefined
  2. a = 2; // 初始化y
  3. // 上面的代码等同于
  4. var a; // 声明y
  5. console.log(a); // 输出undefined
  6. a = 2; // 初始化y

再看一个:

</>复制代码

  1. var a;
  2. console.log(a);
  3. a = 1;
  4. function a() {
  5. // xxx
  6. }
  7. 输出:
  8. /*
  9. function a() {
  10. // xxx
  11. }
  12. 1
  13. */

</>复制代码

  1. javascript永远是先解析声明函数,再解析变量。

执行顺序如下:
(1) 解析函数a;
(2) 声明变量var a; 因为a此时并没有被赋值,所以它为 undefined, 还是指向原来的值,即函数 function a;
(3) console.log(a); // function a
(4) a = 1; // 重新赋值, 输出1

函数重载

</>复制代码

  1. javascript中是没有函数重载的,但是javascript的函数没有限制传入的参数个数必须与函数接收参数的个数相同,所以我们可以利用这一特性来模拟函数重载。

举个栗子:

</>复制代码

  1. function add() {
  2. if (arguments.length < 2) {
  3. return arguments[0];
  4. } else {
  5. var _args = [].slice.call(arguments);
  6. return _args.reduce(function (a, b) {
  7. return a + b;
  8. })
  9. }
  10. }
  11. add(1); // 1
  12. add(1, 2, 3, 4); // 10

举个计算日期的栗子:

</>复制代码

  1. // ..
  2. getFutureDate: function(startDate, afterYear, afterMonth, afterDay) {
  3. var futureDate, year, month, day;
  4. if (arguments.length === 3) {
  5. afterDay = arguments[2];
  6. afterMonth = arguments[1];
  7. afterYear = arguments[0];
  8. startDate = new Date(startDate);
  9. }
  10. if (arguments.length === 4 && Object.prototype.toString.call(startDate) !== "[object Date]") {
  11. startDate = new Date(startDate);
  12. getFutureDate: function (startDate, afterYear, afterMonth, afterDay) {
  13. var futureDate, year, month, day;
  14. if (arguments.length === 3) {
  15. afterDay = arguments[2];
  16. afterMonth = arguments[1];
  17. afterYear = arguments[0];
  18. startDate = new Date(startDate);
  19. }
  20. if (arguments.length === 4 && Object.prototype.toString.call(startDate) !== "[object Date]") {
  21. startDate = new Date(startDate);
  22. }
  23. //计算年
  24. futureDate = startDate.setFullYear(startDate.getFullYear() + parseInt(afterYear));
  25. futureDate = new Date(futureDate);
  26. // 计算月
  27. futureDate = futureDate.setMonth(futureDate.getMonth() + parseInt(afterMonth));
  28. futureDate = new Date(futureDate);
  29. // 计算日
  30. futureDate = futureDate.setDate(futureDate.getDate() + parseInt(afterDay));
  31. futureDate = (new Date(futureDate));
  32. year = futureDate.getFullYear();
  33. month = futureDate.getMonth() + 1;
  34. month = month < 10 ? "0" + month : month;
  35. day = futureDate.getDate();
  36. day = day < 10 ? "0" + day : day;
  37. futureDate = [year, month, day].join("-");
  38. return futureDate
  39. },
  40. initDateTime: function () {
  41. // ...
  42. var endTime = _that.getFutureDate(new Date(today.replace(/-/g, "/")).getTime(), 0, maxInsuranceMonth, maxInsuranceDay);
  43. // ...
  44. }
  45. // ...
Map 函数

</>复制代码

  1. var ary = [1, 2, 3, 4, 5];
  2. var res = ary.map(function (item, index, input) {
  3. return item * 10;
  4. });
  5. console.log(res); // [10, 20, 30, 40, 50]
  6. console.log(ary); // [1, 2, 3, 4, 5]

map 函数的实现:

</>复制代码

  1. Array.prototype.map = function (func /*, obj */) {
  2. var len = this.length;
  3. //check the argument
  4. if (typeof func != "function") {
  5. throw new Error("argument should be a function!");
  6. }
  7. var res = [];
  8. var obj = arguments[1];
  9. for (var i = 0; i < len; i++) {
  10. //func.call(), apply the func to this[i]
  11. res[i] = func.call(obj, this[i], i, this);
  12. }
  13. return res;
  14. }

map:和forEach非常相似,都是用来遍历数组中的每一项值的,用来遍历数组中的每一项;
区别:map的回调函数中支持return返回值;return的是啥,相当于把数组中的这一项变为啥(并不影响原来的数组,只是相当于把原数组克隆一份,把克隆的这一份的数组中的对应项改变了);

前面已经说过,this会指向调用者,所以this是指向需要用到map函数的数组的。
需要注意的是,map函数是接收2个参数的,第二个参数是第一个参数的函数this指向。

柯里化

</>复制代码

  1. 柯里化就是预先将函数的某些参数传入,得到一个简单的函数,但是预先传入的参数被保存在闭包中,因此会有一些奇特的特性。

</>复制代码

  1. var adder = function(num) {
  2. return function(y) {
  3. return num + y;
  4. }
  5. }
  6. console.log(adder(1)(100)); // 101
  7. console.log(adder(2)(100)); // 102

更多内容请翻阅上一篇介绍《邂逅函数柯里化》

递归

递归在编程中会经常使用,在某些时候,递归可以给我们减少很多代码冗余。
比如我们的求阶乘函数:

</>复制代码

  1. function factorial(n) {
  2. if (n == 1) {
  3. return 1;
  4. } else {
  5. return n * factorial(n - 1);
  6. }
  7. }

函数不停的调用自身,来达到不停的向下求值相乘,从而实现阶乘求值。代码逻辑也一目了然。

客户端判断

</>复制代码

  1. var UA = (function (userAgent) {
  2. var ISOldIOS = /OS (d)_.* like Mac OS X/g.exec(userAgent),
  3. isOldAndroid = /Android (d.*?);/g.exec(userAgent) || /Android/(d.*?) /g.exec(userAgent);
  4. // 判断设备是否是IOS7以下
  5. // 判断设备是否是android4.5以下
  6. // 判断是否iOS
  7. // 判断是否android
  8. // 判断是否QQ浏览器
  9. return {
  10. oldIOS : ISOldIOS ? +ISOldIOS.pop() < 8 : false,
  11. oldAndroid: isOldAndroid ? +isOldAndroid.pop().substr(0, 3) < 4.5 : false,
  12. iOS : /(i[^;]+;( U;)? CPU.+Mac OS X/.test(userAgent),
  13. android : /Android/g.test(userAgent),
  14. mQQBrowser: /MQQBrowser/g.test(userAgent)
  15. }
  16. })(navigator.userAgent);

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84677.html

相关文章

  • JS基础常用技巧知识总结(二)

    摘要:组合使用构造函数模式和原型。构造函数用于定义实例属性,原型链用于定定方法和共享的属性。为了避免矛盾和意外的结果总是指定基数参数。 本文主要记录平时开发遇到的知识点和小技巧 原型对象与原型链 JavaScritp 引擎在访问对象的属性时,如果在对象本身中没有找到,则会去原型链中查找,如果找到,直接返回值,如果整个链都遍历且没有找到属性,则返回 undefined.原型链一般实现为一个链表...

    yacheng 评论0 收藏0
  • 前端资源系列(4)-前端学习资源分享&前端面试资源汇总

    摘要:特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方,还请斧正... 托管: welcome to git,欢迎交流,感谢star 有好友反应和斧正,会及时更新,平时业务工作时也会不定期更...

    princekin 评论0 收藏0
  • 个人分享--web前端学习资源分享

    摘要:前言月份开始出没社区,现在差不多月了,按照工作的说法,就是差不多过了三个月的试用期,准备转正了一般来说,差不多到了转正的时候,会进行总结或者分享会议那么今天我就把看过的一些学习资源主要是博客,博文推荐分享给大家。 1.前言 6月份开始出没社区,现在差不多9月了,按照工作的说法,就是差不多过了三个月的试用期,准备转正了!一般来说,差不多到了转正的时候,会进行总结或者分享会议!那么今天我就...

    sherlock221 评论0 收藏0

发表评论

0条评论

dadong

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<