实现instanceof
instanceof
运算符用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值)
要懂原型和原型链
function myInstanceof(target, origin) { if (typeof target !== 'object' || target === null) return false let proto = Object.getPrototypeOf(target) while(proto) { if (proto == origin.prototype) return true proto = Object.getPrototypeOf(proto) } return false }
console.log(myInstanceof("111", String)); console.log(myInstanceof(new String("111"), String));
class People {} class Student extends People {} const stu = new Student(); console.log(stu instanceof People); console.log(stu instanceof Student);
|
JS如何实现继承?
方式1:借助原型链
function Person() { this.name = 'pName' this.age = 18 this.friends = [] }
Person.prototype.sayHello = function() { console.log('Hello'); }
function Student() { this.height = 1.88 }
let p = new Person() console.log(p);
Student.prototype = p
let stu = new Student() console.log(stu.name); stu.sayHello()
|
这种实现方法存在的问题:
1.当我们打印实例stu的时候,继承的属性不能直观看到,只能在__proto__
属性中看到
2.另外,如果我们创建两个实例对象,并改变friends属性
stu1.friends.push('aaa') console.log(stu2.friends);
|
明明改变的是stu1的属性,为什么stu2也变了?
因为我们它们的隐式原型指向的是同一个对象,p
3.前面实现的过程都没有传递参数
方式2:借助构造函数
使用call调用构造函数,传入的this为当前实例,并且可以把参数传给父类处理
function Person(name, age) { this.name = name this.age = age this.friends = [] }
Person.prototype.sayHello = function() { console.log('Hello'); }
function Student(name, age, height) { Person.call(this, name, age) this.height = height }
let p = new Person() Student.prototype = p
let stu1 = new Student('aaa', 18, 1.78) let stu2 = new Student('bbb', 20, 1.88)
stu1.friends.push('aaa') console.log(stu1); console.log(stu2); stu1.sayHello()
|
构造函数的方法可以解决原型链方式的问题,但是依然存在弊端
- Person 至少被调用两次(一开始new Person一次,后面Person.call又会调用Person)
- stu的原型对象上会多出一些属性, 但是这些属性是没有存在的必要(new Person的时候的)
方式3:寄生组合式继承(最终方案)
**Object.create()
**方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
Object.create(XXX) 也就是传入的对象XXX,作为新对象的原型
function Person(name, age, friends) { this.name = name this.age = age this.friends = friends }
Person.prototype.sayHello = function() { console.log('Hello'); }
function Student(name, age, friends, height) { Person.call(this, name, age, friends) this.height = height }
Student.prototype = Object.create(Person.prototype) Student.prototype.constructor = Student
let stu = new Student('aaa', 18, ['fre1'], 1.88) console.log(stu);
|
当然,我们也可以封装一个方法来继承父类prototype中的属性和方法
function inheritPrototype(SubType, SuperType) { SubType.prototype = Object.create(SuperType.prototype)
Object.defineProperty(SubType.prototype, "constructor", { enumerable: false, configurable: true, writable: true, value: SubType }) } ... inheritPrototype(Student, Person)
|
JS柯里化实现
要求,传入一个函数,返回一个柯里化的函数
思路:当已经传入的参数 大于等于 所需要的参数时,就执行函数
没有达到个数时,需要返回一个新的函数,继续来收集参数,接收到参数后,递归调用curried来检查函数的个数是否达到
function myCurrying(fn) { function curried(...args) { if (args.length >= fn.length) { return fn.apply(this, args) } else { function curried2(...args2) { return curried.apply(this, [...args, ...args2]) } return curried2 } }
return curried }
function add1(x, y, z) { return x + y + z }
var curryAdd = myCurrying(add1) console.log(curryAdd(10, 20, 30)); console.log(curryAdd(10)(20, 30)); console.log(curryAdd(10)(20)(30));
|