JS关键字详解
- 本文即是复习,也对新手开发提供参考
- 本文会列举常用的关键字:介绍、使用、并模拟实现
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 = this;
var fNOP = function () {};
var fBound = function () {
fBound.prototype = this instanceof fNOP ? new fNOP() : fBound.prototype;
return fToBind.apply(this instanceof fNOP ? this : oThis || this, aArgs )
}
if( this.prototype ) {
fNOP.prototype = this.prototype;
}
return fBound;
}