bind 实现

  1. bind 是Functoin原型链中Function.prototype的一个属性,每个函数都可以调用它
  2. bind本身是一个函数名为bind的函数,返回值也是函数,函数名是bound +’ ‘ + 函数名
  3. bind 第一个参数是 bind 返回函数的this
  4. bind 其他参数和bind 返回后函数的参数 合并处理了
  5. bind()返回函数 执行后返回值是原函数(original)的返回值
  6. bind函数形参(即函数的length)是 1

Function.prototype.bindFn = function bind(thisArg){
  if(typeof this !== 'function'){
     throw new TypeError(this + ' must be a function');
  }
  // 存储调用bind的函数本身

  var self = this;
  // 去除thisArg的其他参数 转成数组
  var args = [].slice.call(arguments, 1);
  var bound = function(){
    // bind返回的函数 的参数转成数组
    var boundArgs = [].slice.call(arguments);
    var finalArgs = args.concat(boundArgs);
    // new 调用时,其实this instanceof bound判断也不是很准确。es6 
      new.target就是解决这一问题的。
    if(this instanceof bound){
       // 这里是实现上文描述的 new 的第 1, 2, 4 步
       // 1.创建一个全新的对象
       // 2.并且执行[[Prototype]]链接
       // 4.通过`new`创建的每个对象将最终被`[[Prototype]]`链接到这个函数的 
         `prototype`对象上。
       // self可能是ES6的箭头函数,没有prototype,所以就没必要再指向做 
       // prototype操作。

       if(self.prototype){
          // ES5 提供的方案 Object.create()
          // bound.prototype = Object.create(self.prototype);
          // 但 既然是模拟ES5的bind,那浏览器也基本没有实现 
                Object.create()
          // 所以采用 MDN ployfill方案 
          // https://developer.mozilla.org/zh-CN/docs/ Web/ 
          //JavaScript/Reference/Global_Objects/Object/create
          function Empty(){}
               Empty.prototype = self.prototype;
               bound.prototype = new Empty();
           }
          // 这里是实现上文描述的 new 的第 3 步
          // 3.生成的新对象会绑定到函数调用的`this`。
          var result = self.apply(this, finalArgs);
          // 这里是实现上文描述的 new 的第 5 步
          // 5.如果函数没有返回对象类型`Object`(包含`Functoin`, `Array`, 
          //`Date`, `RegExg`, `Error`),
          // 那么`new`表达式中的函数调用会自动返回这个新的对象。
          var isObject = typeof result === 'object' && result !== 
             null;
          var isFunction = typeof result === 'function';

          if(isObject || isFunction){
             return result;
          }
          return this;
        } else {
          // apply修改this指向,把两个函数的参数合并传给self函数,并执行self函 
          // 数,返回执行结果
          return self.apply(thisArg, finalArgs);
        }
     };
   return bound;
}

函数解构默认值


function add([x, y]){
return x + y;
}

add([1, 2]); // 3


//解构后变量默认值
function move({x = 0, y = 0} = {}) {
return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]


//参数 设置默认值
function move({x, y} = { x: 0, y: 0 }) {
return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]

你不知道的javascript

1.  实际上,undefined 值是派生自null值的,因此ECMA-262规定对它们的相等性测试要返回true:

alert(null == undefined); //true

2. 浮点数值的最高精度是17位小数,但在进行算术计算时其精确度远远不如整数。例如,0.1加0.2的结果不是0.3,而是0.30000000000000004。这个小小的舍入误差会导致无法测试特定的浮点数值。例如:

if (a + b == 0.3){ // 不要做这样的测试! alert("You got 0.3."); }

3. 数值转换 有3个函数可以把非数值转换为数值:Number()、parseInt()和parseFloat()。第一个函数,即转型函数Number()可以用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。

Number()函数的转换规则如下。与一元 操作符+有相同效果

  • 如果是Boolean值,true和false将分别被转换为1和0。
  • 如果是数字值,只是简单的传入和返回。  如果是null值,返回0。
  • 如果是undefined,返回NaN。
  • 如果是字符串,遵循下列规则:
  • 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即”1″会变成1,”123″会变成123,而”011″会变成11(注意:前导的零被忽略了);
  • 如果字符串中包含有效的浮点格式,如”1.1″,则将其转换为对应的浮点数值(同样,也会忽略前导零);
  • 如果字符串中包含有效的十六进制格式,例如”0xf”,则将其转换为相同大小的十进制整 数值;
  • 如果字符串是空的(不包含任何字符),则将其转换为0;
  • 如果字符串中包含除上述格式之外的字符,则将其转换为NaN。
  • 如果是对象,则调用对象的 valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是 NaN,则调用对象的 toString()方法,然后再次依照前面的规则转换返回的字符 串值。

parseInt parseFloat

var num1 = parseInt("AF", 16); //175
var num2 = parseInt("AF"); //NaN parseFloat 没有第二个参数只能解析十进制;其他进制会被转成0
var num6 = parseFloat("3.125e7");//31250000

5. toString()可以输出以二进制、八进制、十六进制

6. 位操作符

ecmajavascript 所有数都以 IEEE-754 64位格式存储,但位操作是将64位转换成32的整数执行操作,然后再换回64位

无符号的整数 是32位
有符号的整数 是31位加第32位符号位

正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。

负数也是用二进制码存储, 但使用二进制补码 下面求二进制补码:

  • 1 一个数绝对值的二进制码
  • 2 求二进制反码, 即0 替换1, 1 替换0, 符号位不变
  • 3 得到的二进制反码加1 就是补码
  1. 按位非(NOT) 就是求反码 用 ~ 表示
  2. alert(~ 25) // -26 也就是25的负数二进制码 再减1 就是25的反码, 所以-25 -1
  3. 按位与(AND)用 & 表示
  4. 两个数值的对应位都是1 时才返回1,任何一位为0 都返回0
  5. alert(25 & 3) // 1
  6. 3 按位或(OR) 用 | 表示
  7. 两个数值的对应位有一个是1 就返回1
  8. alert (25 | 3) // 27
  9. 按位异或(XOR) 用 ^ 表示
  10. 两个数值对应位上 只有一个1时才返回1, 都是1或0 返回0
  11. alert (25 ^ 3) // 26
  12. 左移 用 << 表示, 左移不会影响符合位 2 << 5 // 64 2左移5位空出来的 用 0 补空位, 换算成十进制是 64 6 右移 用 >> 表示 右移出现的空位用符号位的值来补充

7. 传递参数

所有参数是按值传递的

function setName(obj){
   obj.name= 'nich';
   obj = new Object();
   obj.name = 'greg'
}
var person = {};
setName(person);
alert(person.name) // nich
//即使按值传递, obj 也会按引用访问同一个对象;
// 如果person 按引用传递的, 那name 属性值为greg,

8. 迭代方法

arr.every((val [,index] [,array]) => val ===1) //  每一项都是true 才返回true
arr.some() // 其中一项为true 就返回true

Function

函数内部属性 arguments 和 this

1.arguments 主要用途保存函数参数, 这个对象还有一个交 callee 的属性,该属性是个指针,指向arguments 的函数

 // 严格模式下反问 callee 会报错 
// 利用callee 阶乘
function factorial(num) {
  if(num <= 1){
    return 1;
  } else {
    return num * arguments.callee(num -1)
  }
}

2. caller 保存着调用当前函数的函数的引用, 严格模式会报错
argument.callee.caller 指向 调用arments 函数的函数

3. call 第二个参数可以是数组 可以是arguments 对象

Number

toPrecision(2) 方法 根据参数位数,返回最合适的格式表达数字

String

1 split()

var colorText = 'red, bule, green, yellow';
var colors = colorText.split(/[^\,]+/); // ['', ',', ',', ',', '']

2 replace()

function htmlEscape(text){
  return text.replace(
       /[ <>"&]/g, 
      function(macth, pos, originText){ 
        // 每一次的匹配项, 位置, 原始字符串
        switch(match){
          case "<"
        return "&lt"
        }
      }
 )
}

Object 操作符

原型与in 操作符
无论是实例属性还是原型属性 都会返回true
‘name’ in obj

  • obj.hanOwnProperty(‘name1’) name1只有存在于实例中的属性才返回true
  • 对象添加实例属性会屏蔽原型中属性, 但delete 后, 就会返回原型中的属性
  • for in 遍历enumerated 的属性, 既包括实例中也包括原型中的属性
  • Object.keys() 返回一个可枚举属性(包括方法)的字符串数组, 如果是对象只包含实例属性

function

函数创建时,会预先创建一个包含全局变量的作用域链, 这个作用域链被保存在函数内部 [[scope]],
当调用函数时, 会为函数创建一个执行环境,通过复制函数的[[scope]]属性中的对象构建起执行环境的作用域链,
此后又有一个活动对象(也就是函数的参数对象)被创建并推出执行环境作用域链的前端。

  • 作用域链的本质是一个指向变量对象的指针列表,只是引用
  • 闭包:有权访问另外一个函数作用域中的变量的函数
  • 闭包的作用域链包含外部函数的作用域链

闭包中的this 返回 window 问题:

  • 函数调用时会自动获取两个特殊变量 this和arguments
  • 闭包搜索这两个变量时, 只会搜索到其活动对象为止, 因此永远不能访问外部函数的这两个对象
var object = {
  name: 'my object',
  getName: function(){
    return function(){
      this.name // undefined
    }
  }
}
object.getName()() // undefined