JS关键字详解

130 阅读3分钟

JS关键字详解

  1. 本文即是复习,也对新手开发提供参考
  2. 本文会列举常用的关键字:介绍、使用、并模拟实现

instanceof

instanceof运算符返回一个布尔值,表示对象是否为某个构造函数的实例

但是不能用来判断变量是不是对象

  • 示例一
function Person(){
  this.name="wang";
}
var p1=new Person();
console.log( p1 instanceof Person);//true
  • instanceof运算符的左边是实例对象,右边是构造函数。它会检查右边构造函数的原型对象(prototype),是否在左边对象的原型链上。因此,下面这种写法是等价的。
console.log(Person.prototype.isPrototypeOf(p1));//true
  • instanceof()是检测整个原型链,所以一个对象可能对多个构造函数返回true
console.log( p1 instanceof Object);//true

注意

  • 但是有一种情况,左边为null,或者左边对象的原型链上只有null对象时,这时,instanceof会判断失真
null instanceof Object // false
typeof null // object
undefined instanceof Object // falase
typeof undefined // undefined
var obj = Object.create(null);
typeof obj // "object"
obj instanceof Object // false
  • instanceof()还有一种用法用于判断值的类型,但只能用于对象,不能用于原始类型(字符串 数值 布尔)的值。
var x = [1, 2, 3];
var y = {};
console.log( x instanceof Array )// true
console.log(y instanceof Object)  // true

call和apply的模拟实现

call

call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。
语法:fun.call(thisArg[,arg1[,arg2,…]]);

Function.prototype.call2 = function (context) {
  // 1. 解决 abc.call() || abc.call(null,1) 的情况
  var context = context || window;
  // 2. this 代表调用这个函数的方法 Symbol 保证唯一性
  var fn = Symbol();
  context[fn] = this;
  // 3. 获取除了context 之外的参数。当然也可以用...args
  var args = [];
  for (var i = 1, len = arguments.length; i < len; i++) {
    args.push("arguments[" + i + "]");
  }
  // 4. 执行js函数(数组当做字符串相加,结果是,号隔开形式)
  var result = eval("context[fn](" + args + ")");
  // 5. 删除多余的方法
  delete context[fn];
  // 6. 返回值
  return result;
};

// 测试一下
var value = 2;

var obj = {
    value: 1
}

function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}

bar.call(null); // 2

console.log(bar.call2(obj, 'kevin', 18));
// 1
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

call实现继承

function Person(name, age){
  this.name = name;
  this.age = age;
  this.say = function(){
    console.log(this.name + ":" + this.age);
  }
}
function Student(name, age, job){
  Person.call(this, name ,age);
  this.job = job;
  this.say = function(){
    console.log(this.name + ":" + this.age + " " + this.job);
  }
}
var me = new Student("axuebin",25,"FE");
console.log(me.say()); // axuebin:25 FE

apply

apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数。
语法: fun.apply(thisArg, [argsArray]);

Function.prototype.myapply = function (context, arr) {
  var context = context || window;
  var fn = Symbol();
  context[fn] = this;
  
  var result;
  if (!arr) {
    result = context[fn]();
  } else {
    var args = [];
    for (var i = 0, len = arr.length; i < len; i++) {
      args.push("arr[" + i + "]");
    }
    result = eval("context[fn](" + args + ")");
  }

  delete context[fn];
  return result;
};

bind

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
语法: fun.bind(thisArg[, arg1[, arg2[, ...]]])

Function.prototype.bind2 = function (context) {
  if (typeof this !== "function") {
     throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
  }
  // 1. 获取绑定函数
  var self = this;
  // 2. 获取参数
  var args = Array.prototype.slice.call(arguments, 1);
  // 3. 创建返回函数
  var fbound = function () {
    // 当作为构造函数时,this 指向实例,self 指向绑定函数,因为下面一句 `fbound.prototype = this.prototype;`,已经修改了 fbound.prototype 为 绑定函数的 prototype,此时结果为 true,当结果为 true 的时候,this 指向实例。
    // 当作为普通函数时,this 指向 window,self 指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的 context。
    var bindArgs = Array.prototype.slice.call(arguments);
    self.apply(this instanceof self ? this : context, args.concat(bindArgs));
  };
  // 4. 我们直接将 fbound.prototype = this.prototype,我们直接修改 fbound.prototype 的时候,也会直接修改函数的 prototype,这样并不好。这个时候,我们可以通过一个空函数来进行中转:
  var fNOP = function () {};
  fNOP.prototype = this.prototype;
  // 5. 更改原型蓝,用于fbound中的 instance判断
  fbound.prototype = new fNOP();
  // 6. 返回函数
  return fbound;
};
// MDN的Polyfill
Function.prototype.bind = function (oThis) {
  var aArgs = Array.prototype.slice.call(arguments, 1);
  var fToBind = thisvar fNOP = function () {};
  var fBound = function () {
    fBound.prototype = this instanceof fNOP ? new fNOP() : fBound.prototypereturn fToBind.apply(this instanceof fNOP ? this : oThis || this, aArgs )
  }   
  if( this.prototype ) {
    fNOP.prototype = this.prototype;
  }
  return fBound;
}