为了更好的理解后面的内容,我们先来了解一些前置知识吧!
构造函数和普通函数的区别
构造函数:
使用一个函数来初始化对象,并配合new使用,则我们称这个函数为构造函数
普通函数
作为一个函数,除了构造函数之外就是普通函数了,详细大家用的比我熟练
构造函数和普通函数的区别
语法上没有区别!!!唯一的区别就是使用上的区别,使用上如何区别二者呢?使用了函数前面有一个new关键字,那就是构造函数,只要记住这一点就行了!
普通函数怎么使用呢?我就不在关公面前耍大刀了
进行分析new的过程,主要有以下几点
- 创建一个新的对象
- 把obj的__proto__指向fn的prototype,实现继承
- 改变this的指向,执行构造函数、传递参数,fn.apply(obj,)或者 fn.call()
- 返回新的对象obj
我们来看一下构造函数怎么使用吧!
function Person(name, age){
this.name = "codingkid";
this.age = 18;
}
var person = new Person();
- 创建一个空对象
var person = {}
- this变量指向对象p
Person.call(p)
关于call的用法并不难,可以去找一些参考资料
- person除了有了Person函数中定义的变量外,还继承了Person()的原型,也就是可以使用Person()中原型的变量和方法,
person._proto_ = Person.prototype
由此可看构造函数就是比普通函数多了些操作,这些多的操作无疑和new关键字有很大的关系
不过需要细想几个问题
- 第一个是关于this的问题,进行了上述过程后,构造函数中的this绑定了person对象,但普通函数却没有绑定对象,其实函数本质上也就相当于一个对象的属性,在全局下声明的函数相当于省略了window,不过是window的一个属性,所以调用时会指向window,在其他对象中声明的函数可类似此过程。
- 构造函数会返回一个新的对象,所以不会在构造函数中使用return语句,如果使用了return语句,则会根据return值的类型而有所不同,原本没有如return会返回一个对象,对象是一个应用类型,所以当显示使用return返回应用类型的话,会生效,否则会失效,依旧返回声称的对象。普通函数的return正常用就行了。
实现new
手动实现
var New =function(fn){
var obj={};
obj.__proto__=fn.prototype;
// 将 arguments 对象转为数组
var args = [].slice.call(arguments);
//去除构造函数
args.shift();
// 执行构造函数并改变this对象
var result = fn.apply(obj, args);
if(Object.prototype.toString.call(result)=="[object Object]" ){
return result
}else{
return obj;
}
}
测试
var New =function(fn){
var obj={};
obj.__proto__=fn.prototype;
// 将 arguments 对象转为数组
var args = [].slice.call(arguments);
//去除构造函数
args.shift();
// 执行构造函数并改变this对象
var result = fn.apply(obj, args);
if(Object.prototype.toString.call(result)=="[object Object]" ){
return result
}else{
return obj;
}
}
var Fn=function(sex){
this.name='hty';
this.sex=sex;
}
//返回一个对象
var Fn1=function(){
this.name='hml';
return {
name:'hty1'
}
}
//返回非对象
var Fn2=function(){
this.name='hty3';
return 1000
}
const fn=New(Fn,'123');
console.log(fn.name);//hty
console.log(fn.sex);//123
const fn1=New(Fn1)
console.log(fn1.name);//hty1
const fn2=New(Fn2)
console.log(fn2.name);//hty1
这里我写了一个例子,大家可以看看
<script>
/*
@author: zft
@title: 如何实现一个 new
@data:2020.10.5
*/
function Dog(name) {
this.name = name
this.say = function () {
console.log('name = ' + this.name)
}
}
function Cat(name) {
this.name = name
this.say = function () {
console.log('name = ' + this.name)
}
}
function _new(fn, ...arg) {
const obj = {}; //创建一个新的对象
obj.__proto__ = fn.prototype; //把obj的__proto__指向fn的prototype,实现继承
fn.apply(obj, arg) //改变this的指向
return Object.prototype.toString.call(obj) == '[object Object]'? obj : {} //返回新的对象obj
}
//测试1
var dog = _new(Dog,'aaa')
dog.say() //'name = aaa'
console.log(dog instanceof Dog) //true
console.log(dog instanceof Cat) //true
//测试2
var cat = _new(Cat, 'bbb');
cat.say() //'name = bbb'
console.log(cat instanceof Cat) //true
</script>