如何实现一个Bind
最简方式
通过给目标函数指定作用域来简单实现bind()方法
Function.prototype.bind = function(context){
self = this;
return function(){
return self.apply(context,arguments);
}
}
复制代码
考虑到函数科里化的情况
Function.prototype.bind = function(context){
var args = Array.prototype.slice.call(arguments);
self = this;
return fucntion(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return self.apply(context,finalArgs)
}
}
复制代码
知识点:
函数科里化
function add (a,b,c){
var i = a+b+c;
console.log(i);
return i;
}
var func = add.bind(undefined,100) ; // 给add()传了第一个参数a
fucn(1,2); // 103,继续传入b和c
var func2 = func.bind(undefined,200);//给func2传入第一个参数,也就是b, 此前func已有参数a=100
func2(10);//310,继续传入c,100+200+10
复制代码
这是高阶函数的一种特殊用法
柯里化是指这样一个函数(假设叫做createCurry),他接收函数A作为参数,运行后能够返回一个新的函数。并且这个新的函数能够处理函数A的剩余参数。
Array.prototype.slice.call(arguments)
Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组
var a={length:2,0:'first',1:'second'};
Array.prototype.slice.call(a);// ["first", "second"]
var a={length:2};
Array.prototype.slice.call(a);// [undefined, undefined]
复制代码
首先,slice有两个用法,一个是String.slice,一个是Array.slice
第一个返回的是字符串,第二个返回的是数组,这里我们看第2个。
Array.prototype.slice.call(arguments)能够将arguments转成数组,那么就是arguments.toArray().slice()。
Array.prototype.slice.call(arguments,1)
slice返回一个数组,该方法只有一个参数的情况下表示除去数组内的第一个元素。这里是去掉函数自己的方法名
obj = {
a1:function(){}
}
即去掉a1,只取参数。
复制代码
考虑到构造函数的情况
Function.prototype.bind = function(context){
var args = Array.prototype.slice(arguments, 1),
self = this,
F = function(){},
bound = function(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return self.apply((this instanceof F ? this : context), finalArgs);
};
F.prototype = self.prototype;
bound.prototype = new F();
retrun bound;
};
复制代码
通过设置一个中转构造函数F,使绑定后的函数与调用bind()的函数处于同一原型链上,用new操作符调用绑定后的函数,返回的对象也能正常使用instanceof,因此这是最严谨的bind()实现
如何实现一个New
- 新生成了一个对象
- 新对象隐式原型链接到函数原型
- 调用函数绑定this
- 返回新对象
核心代码
首先写一个父类
function Person(name,age){
this.name = name;
this.age = age;
}
复制代码
自定义一个New函数
//通过分析原生的new方法可以看出,在new一个函数的时候,
// 会返回一个func同时在这个func里面会返回一个对象Object,
// 这个对象包含父类func的属性以及隐藏的__proto__
function New(f) {
//返回一个func
return function () {
var o = {"__proto__": f.prototype};
f.apply(o, arguments);//继承父类的属性
return o; //返回一个Object
}
}
复制代码
优先级问题
优先级由高到低:==小括号(xxx) > 属性访问. > new foo() > foo()==
属性访问.和new foo() 同为18级,按从左到右先访问的顺序
new foo() 和 new foo 的区别在于new的有参和无参方式,有参18级大于无参17级。
根据上面面试题整理的知识点:
函数的方法
function User(name) {
var name = name; //私有属性
this.name = name; //公有属性
function getName() { //私有方法
return name;
}
}
User.prototype.getName = function() { //公有方法
return this.name;
}
User.name = 'Wscats'; //静态属性
User.getName = function() { //静态方法
return this.name;
}
var Wscat = new User('Wscats'); //实例化
复制代码
- 调用公有方法,公有属性,我们必需先实例化对象,也就是用 new 操作符实化对象,就可构造函数实例化对象的方法和属性,并且公有方法是不能调用私有方法和静态方法的
- 静态方法和静态属性就是我们无需实例化就可以调用
- 而对象的私有方法和属性,外部是不可以访问的