javascript冷知识

本人很少写博客,所以文笔很不好,如果解释的不够清楚的,欢迎点评

1.+号(一元加操作符):

  如果放在数值前的话,对数值不会产生任何影响,不过放在其他的数据类型前面的话,就等于调用number()将他转为数字,布尔值false被转为0,ture被转为1

  如, +"1.1" =  1.1 ,对象则会调用它的valueof()或者toString()函数,然后再转为数值

2.parseInt:可以用它来指定数据的类型,如 parseInt("12", 8) // 10 第二个参数为进制

   parseFloat: 只有一个参数:要转的字符串,只能转为十进制

3.一元减操作符:与+号的一样的原理,不过就是变为相反数

4.toString操作:

  可以利用它将数值转为不同进制

  ex: var i = 10;  i.toString(16) // 'a'  转为十六进制

5. >> (右移)和<<(左移)操作都不会改变符号位,但是 >>> 则会连符号位一起移动

6.

  逻辑或操作符 || 返回的是操作数,而不是true or false.

  ex:

   var a = "test";

   var b = a || c // b = "test" 

     var b = null || a  // b = "test"

7 将一个数值与一个字符串相加的话,等于把这个数值添加到字符串中

 var result = "5" + 5;  // result = "55"

  将一个数值减去一个字符串的话,这个字符串会被转化为数字进行运算。

 var result = 5 - "1" // result = 4

8. < 比较符

  因此,  2 < "3" // true "3" > "23" // true

  但是,任何与NaN比较的结果都返回false,如 'a' > 12 // false 'a' <= 12 // false

9.with语句:将代码的作用域设置到一个特定对象中,如

  var ps = location.search

  var hostName = location.hostname

  var url = location.href

  // 我们可以用with改为

  with(location) {

    var ps = search

    var hostName = hostname

    var url = href

  }

10.javascript 没有重载函数。前一个函数会被最后一个覆盖掉

  function test1() {

    console.log("before");

  }

  function test1(params) {

    console.log("after");

  }

  test1(); // after; 前面那个函数被覆盖掉了

  可以用arguments.length获取输入的参数数目,arguments[i]来获取第i个参数

11.赋值运算的时候,若是基本类型的赋值,则等于创建了一个新值,若是引用类型(对象)的赋值,则两个会指向同一个对象

  var i = 5;

  var b = i;

  i = 4// i = 4, b = 5

     var obj1 = new Object();  

  obj2 = obj1; 

  obj1.t = "asd";

  obj2.t // "asd"  两个指向同一个对象,所以obj1改变了,obj2也跟着改变

  函数传参也是一样,基本类型就等于创建个新值,引用类型就会指向同一个对象,但是是按值传递,只不过只是指向的地址相同,如果在函数里面让他等于一个新对象的话,那么外面的不会受到影响

12 使用instance来判断对象是什么类型的 // 数组的话,可以用Array.isArray(value)的方法来判断

13.javascript没有块级作用域,因此

  if (i = 1) { var result = "test" } console.log(result) // "test" 

  可以通过函数来解决这个问题,在函数内部定义的局部变量,外部访问不到

14.访问对象的属性的时候,可以通过.或者[],例如

  var i = { name : "test" } i.name == i["name"]

  如果属性名包括会导致语法错误的字符 或者属性名使用的是关键字或者保留字,则使用方括号方法。

  person['first name'] = 'CJG'  // 不能用.号运算符

15 Array.sort():

  该函数会将数组的每一项转化字符串,然后再进行比较,这就会导致一个问题:

    var values = [0,1,5,10,15] values.sort(); // 0, 1, 10, 15, 5

  解决方法: 它可以接受一个函数参数,因此我们可以自己写一个比较函数:

  function cmp(value1, value2) {return value2 - value1;}

  然后values.sort(cmp) // 0, 1, 5, 10, 15

  因此,我们可以自己写函数来决定它的排序方法

16 数组常用操作: 

  concat: 基于当前数组的内容,创建一个新的数组

    var i = [1,2,3]

    var b = i.concat[4,[6,8]] // [1,2,3,4,6,8]

  slice: 基于当前数组的一或多个项创建新数组

    var i = [1,2,3,4]

    var b=  i.slice(1) // [2,3,4]

    var c = i.slice(1,3) // [2,3]

  splice: 用来删除数据(前两个参数,删除的项的位置以及删除的数目)或者插入数据(三个参数,起始位置,0,以及要插入的项)或者替换(三个参数,起始位置,1,要插入的任意数量的项)

    var i = [1,2,3,4]

    var b = i.splice(0,1) // b = [1] i = [2,3,4]

17 函数内部,有两个特殊的对象:arguments 和 this, argument除了保存着函数参数之外,还有一个属性callee,这个属性指向拥有这个对象的函数。

  例如,斐波那契数列可以这样写,我们用callee将他改变下

  function factorial(num) {

    if(num <= 1) {

      return 1;

    } else {

      return num * factorial(num-1);

    }    

  }

  //改进

  function factorial(num) {

    if(num <= 1) {

      return 1;

    } else {

      return num * arguments.callee(num-1);

    }   

  }

  这样做的好处是什么呢?在于,你无论你的函数名怎么变,这一段代码都能生效。

  假设你这样写:

    var trueFactorial = factorial;

    factorial = funcion() {

      return 0;

    }

    trueFactorial(5) // 如果我们用改进的版本,输出为120,否则,则为0

    factorial(5) // 0

18.函数有两个非继承(不在prototype里)的方法:apply和call

  apply接受两个参数,第一个是运行这个函数的对象(作用域),第二个是一个参数数组(也可以是一个arguments对象),指的是这个函数运行所需要的参数

  function sum(num1, num2) {

    return num1 + num2;

  }

  function test(num1, num2) {     return sum.apply(this, arguments); //和下面的代码结果是一样的

    //return sum.apply(this, [num1,num2])

  }

  test(1,2) // 3  由于是在全局作用域用的,这个时候this是window对象

  call 和apply的作用是相同的,第一个参数是一样的,不同的是,参数是直接传递给函数,这个时候test的代码应该改为

  return sum.call(this, num1, num2);

  当然,他们的作用不只局限于而已。他的作用在于,我们可以扩展他的作用域。如

  function sayColor() {

    console.log(this.color);

  }

  var color = "red";

  var t = { color : "blue" }

  sayColor.call(this); // red

  sayColor.call(t); // blue

19.

20.ECMAscript有两种属性:数据属性和访问器属性,数据属性有: 

要改变属性默认的特征,必须使用ECMAscript5的Object.defineProperty().

具体用法如下:

(1)

  var person = { }

  Object.defineProperty(person, "name", {

    writeable: false, // 让这个属性不能重写,只读

    value: "CJG“  // 给属性赋一个默认值

  }

   console.log(person.name) // 'CJG'

  person.name = 'ZHT';

  console.log(person.name) // 'ZHT' 只读,不能改

(2)

  var person = { }

  Object.defineProperty(person, "name", {

    configurable: false, // 让这个属性不能被删除

    value: "CJG“  // 给属性赋一个默认值

  }

   console.log(person.name) // 'CJG'

  delete person.name = 'ZHT';

  console.log(person.name) // 'ZHT' 只读,不能改

21.在创建自己类时候,最好使用动态原型模式,如

  function Person(name, age, job) {

    this.name = name;

    this.age = age;

    this.job = job;

    //定义方法的做法

    if (typeof this.sayName != function) {

      Person.prototype.sayName = function() {

        alert(this.name)

      }

    }

  }

  var person1 = new Person("CJG", 20, 'student');

  var person2 = new Person("ZHT", 20, "student");

  person1.sayName(); // CJG

  person1.name = "CJG11"

  person1.sayName(); // CJG11

  person2.sayName(); // ZHT

优点:每一个实例都有自己的一些变量,但是他们又共享同一个方法,这样就可以节省空间。

22.对象继承:

  组合继承方法:

    function Super(name) {

      this.name = name;

      this.color = ['blue', 'red', 'green'];

    }

    super.sayName = function() {

      console.log(this.name);

    }

    function sub(name, age) {

      Super.call(this, name);

      this.age = age;

    }

    sub.prototype = new Super();  // sub类的原型为Super的实例

    sub.prototype.sayAge = function() {

      console.log(this.age);

    }

    var subtest = new sub("CJG", 20);

    subtest.sayAge(); // 20

    subtest.sayName(); // name

    subtest.color.push("pink") // ['blue', 'red', 'green', 'pink'];

    var subtest1 = new sub("ZHT", 20)

    console.log(subtest1.color) // ['blue', 'red', 'green']

     好处:子类继承了父类的方法,并且每一个子类都拥有父类的属性副本,属性不共享,方法共享

    缺点: 调用了两次父类的构造函数(第一次在sub的构造函数上,第二个在sub.prototype赋值上)。实际上,子类拥有两个版本的父类的属性副本,第一个版本在subtest上,第二个版本在subtest.prototype上,第一个版本掩盖了第二个版本

    原型链图如下:

  改进方法:

   寄生组合式继承:

 23.函数表达式的问题:

  //可以正常运行

  sayHi(); // 代码在执行前,会先读取函数声明,也就是会先找到函数声明在来执行这一段代码

  function sayHi() {

    console.log("Hi"); // 这个是函数声明

  }

  //报错

  sayHi(); 

  sayHi = function() {

    console.log("Hi"); // 这个是函数表达式

  }

24.闭包:指有权访问另一个函数作用域的变量的函数

  function sayName() {

    name = "CJG"

    return function() {

      console.log(name);

    }

  }

  var s = sayName();

  s(); // CJG

  在上面这个例子中,sayName中的匿名函数可以访问sayName的变量(访问了另一个函数作用域的变量),一般来说,一个函数运行完后,他的作用域就会被移除,所以name应该是访问不到的。可是为什么能正常运行呢?

  原因:在闭包中,由于匿名函数调用了sayName里的变量,将它的变量加到自己的作用域内,所以如果它存在的话,sayName的变量就不会消失.我们可以通过将s=null来解除对匿名函数的引用,以此来释放内存

  闭包的问题:

    //这个函数的作用是,创建一个函数数组,第i个函数输出i

    function sayI() {

      var result = [];

      for (var i = 0; i < 10; i++)

        result[i] = function() {

          console.log(i);

        }

      return result;

    }

    var result = sayI();

    result[3](); // 10

  Why?为什么不是输出3?原因是,每一个函数输出的值为i,而i最后循环变为10.因此,每一个函数的输出都是10

  解决:

  function sayI() {

    var result = [];

    for (var i = 0; i < 10; i++)

      result[i] = function(num) {

        return function() {

          console.log(num);

        }

      }(i)

    return result;

  }

  var result = sayI();

  result[3](); // 3

  在这里,我们再次用了闭包,将i的值传递给这个函数.

  除此之外,闭包还存在一个问题:占用很多内存

  function assignHandler() {

    var element = document.getElementById("content");

    element.onclick = function() {

      console.log(element.id);

    }

  }

  调用这个函数的时候,为"content"这个元素增加了一个onclick事件。这看起来没什么问题,但是,由于在那个匿名函数里面调用了另一个函数的变量(element.id),因此构成了闭包。这就导致了,element这个变量无法被回收。

 解决: 

  function assignHandler() {

    var element = document.getElementById("content");

    var id = element.id;

    element.onclick = function() {

      console.log(id);

    }

    element = null;

  }

   由于只要匿名函数有调用到assignHandler的变量,因此assignHandler里面的所有变量都不会消失。因此我们可以通过设置element=null来手动回收他

25.window对象:所有在全局作用域声明的变量,函数都会成为他的变量和函数。不过,在全局变量里声明的变量或者函数不能删除,而在window上声明的可以删除。

26.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏coding for love

JS入门难点解析12-继承的实现方式与优缺点

(注1:如果有问题欢迎留言探讨,一起学习!转载请注明出处,喜欢可以点个赞哦!) (注2:更多内容请查看我的目录。)

1472
来自专栏空帆船w

Java 反射基础

最近在调研 Android 应用加固方案,涉及大量反射技术,因此趁这个机会总结下 Java 反射的一些知识。

952
来自专栏平凡文摘

深入理解Java类型信息(Class对象)与反射机制

1243
来自专栏Android知识点总结

TIII-Android技术篇之反射

1005
来自专栏Ryan Miao

Java复习3-类的继承

本次学习面向对象设计的另外一个基本概念:继承(inheritance)。这是Java程序设计中的一项核心技术。另外,还要学习反射(reflection)的概念。

1002
来自专栏源哥的专栏

一个用来保存参数的容器类

793
来自专栏老马说编程

(84) 反射 / 计算机程序的思维逻辑

上节介绍完了并发,从本节开始,我们来探讨Java中的一些动态特性,包括反射、类加载器、注解和动态代理等。利用这些特性,可以以优雅的方式实现一些灵活和通用的功能,...

2418
来自专栏java技术学习之道

java反射详解

1405
来自专栏猿学

猿学-深入理解Java中的反射机制

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对...

330
来自专栏水击三千

浅谈JavaScript的面向对象程序设计(一)

  面向对象的语言有一个标志,他们都有类的概念,通过类可以创建多个具有相同属性和方法的对象。但是JavaScript中没有类的概念,因此JavaScript与其...

2717

扫码关注云+社区