神奇的new操作符

在使用new操作符实例化构造函数的时候,你有没有产生过困惑究竟new操作符帮我们做了什么?接下来我们就来揭开它的神秘面纱,来看一下其内部究竟是怎么运行的。

我们先看一个例子:
function Person(name,age){
    this.name=name;
    this.age=age;
}
Person.prototype.getPerson=function(){
  console.log(this.name+‘的年龄是‘+this.age);
};

new实例化,调用getPerson方法,我们得到了‘张三的年龄是13’的结果

var zhangSan=new Person(‘张三‘,‘13‘);
zhangSan.getPerson();   //张三的年龄是13
那么这整个过程究竟是怎样的呢?接下来我们就来详细分析一下,首先 new Person(‘张三‘,‘13‘) 实例化的过程:
function new2(func){
    //创建一个对象
    var newObject={};
    //设置原型链
    newObject._proto_=func.prototype;
    //修改this指向新对象newObject,并执行函数体func
    var result=func.apply(newObject,arguments);
    //判断函数体的返回类型,如果是引用类型,返回这个引用类型
    if(result instanceof Object){
        return result;
    //否则,返回新对象newObject
    }else{
        return newObject;
    }
}
这个过程只是模拟理解,实际上实例对象有一个内部属性[[Prototype]]指向构造函数的原型对象,而脚本中并没有标准的方式访问[[Prototype]],但 Firefox、Safari 和 Chrome 在每个对象上都支持一个属性__proto__;而在其他实现中,这个属性对脚本则是完全不可见的

有的同学可能会困惑new操作符实例化返回的结果不都是一个新的对象吗?我们来试验一下:
function Person(name,age){
    this.name=name;
    this.age=age;
    return {
        ‘aaa‘:‘哈哈哈,我是不是很奇怪‘
    }
}
Person.prototype.getPerson=function(){
    console.log(this.name+‘的年龄是‘+this.age);
};

console.log(new Person(‘张三‘,‘13‘)); //{‘aaa‘:‘哈哈哈,我是不是很奇怪‘}
上面的结果返回了对象{‘aaa‘:‘哈哈哈,我是不是很奇怪‘},所以一般情况下构造函数不返回任何值。
了解了new操作符内部的工作原理,我们就来看一下zhangSan.getPerson()调用方法的这个过程,细心的同学可以留意到getPerson这个方法我们绑在了构造函数的原型上,而实例化的对象本身并没有这个方法,那么它是怎样调用并得到了我们想要的结果呢?

答案就是我们刚刚分析的new操作符的工作原理,实例化的对象有一个内部属性[[Prototype]],指向构造函数的原型对象,当我们调用某一个方法时:1.都会先执行第一次搜索:实例化对象本身有无此方法,如果有,则返回实例化对象本身定义的方法调用;2.如果无,则执行第二次搜索,内部属性[[Prototype]]指向的构造函数的原型对象,如果能找到,则返回原型中的定义的方法调用,如果没有,则会报错。

在本示例中,则是返回了原型中定义的方法调用,得到了‘张三的年龄是13’的结果。

这个过程的模拟代码如下:
function getProperty(obj, prop) {
  if (obj.hasOwnProperty(prop))
    return obj[prop]

  else if (obj.__proto__ !== null)
    return getProperty(obj.__proto__, prop)

  else
    return undefined
}

参考资料:

1.Javascript – How Prototypal Inheritance really works

2.new运算符

				
时间: 2024-08-26 15:13:22

神奇的new操作符的相关文章

神奇的位操作符

相信学过C语言的小伙伴们都知道位操作符,正确的使用位操作符会让我们写出更高效率的程序 但不要忘记它也是有缺点的:只能用于整型和字符型数据. 速度:快于乘法 等同于加减法 *参与运算的数据以补码形式出现!(不要弄错啦!) eg: 数字 -1 原码:10000000 00000000 00000000 00000001 反码:11111111 11111111 11111111 11111110 补码:11111111 11111111 11111111 11111111 ***有符号数只改变数值部

javascript中神奇的(+)加操作符

javascript是一门神奇的语言,这没神奇的语言中有一个神奇的加操作符. 常用的加操作符我们可以用来做: 加法运算,例如:alert(1+2); ==>3 字符串连接,例如:alert(“a”+”b”);==>”ab” 高级一点的还有“+=”,也是做以上两种操作的. 昨天在javascript丛林群里问了问题:怎么把“2000-09-11 19:22”这个日期格式字符串转换成毫秒数? 斩梦人天天马上回答我: +new Date(‘2000-09-11 19:22′),试了一下不行,正确的应

Python爬取CSDN博客文章

之前解析出问题,刚刚看到,这次仔细审查了 0 url :http://blog.csdn.net/youyou1543724847/article/details/52818339Redis一点基础的东西目录 1.基础底层数据结构 2.windows下环境搭建 3.java里连接redis数据库 4.关于认证 5.redis高级功能总结1.基础底层数据结构1.1.简单动态字符串SDS定义: ...47分钟前1 url :http://blog.csdn.net/youyou1543724847/

转载:Python的神奇方法指南:使操作符在自定义类内工作

使用 Python 神奇方法的优势之一就是它提供了一种简单的方式能让对象的行为像内建类型.这意味着你可以避免用丑陋,反直觉和非标准方法执行基本运算.在某些语言中,通常会这样做: if instance.equals(other_instance): # do something 你也应该在 Python 确实会这样做,但同时它会增加用户的疑惑以及不必要的冗长.不同的库可能会对相同的运算采用不同的命名,这使得用户比平常干了更多的事.依靠神奇方法的力量,你可以定义一个方法(比如 __eq__),然后

一行神奇的javascript代码

写本篇文章的缘由是之前群里有朋友发了一段js代码,如下: (!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]] 然后让大家运行,出来的结果让人有点出乎意料,请看: 太风骚了有木有!如果有人诋毁前端瞧不起js的话,那就可以把这段代码发给他了~ 不过话说回来了,这到底是什么原理呢?为什么一堆符号运算结果竟然能是两个字符,而且恰巧还是个sb! 其实靠的是js的类型转化的一些基本原理,本篇就来揭密"sb&q

神奇的Grails:自关联的树状Domain一行代码获取所有子节点

见证Groovy/Grails的神奇时刻到了,你相信吗?用一行代码就可以获取树状结构中某节点下的所有全部子节点!注意:这个树是无深度限制的.无深度限制这点很重要,如果有限深度的树,那我们也很容易通过层级编码用“Like 001%”方式实现(维护编码也是一个有挑战性活).我们以一个非常常见的“类别”Domain为例,大类分小类,小类再细分,典型的树形结构,看看Grails是如何以简洁的语法表达的,体验Groovy语法的神奇! class Group{ String name static hasM

#define中 #与##的神奇用法linux学习 (转)

#define中 #与##的神奇用法linux学习 (转) #define f(a,b) a##b #define d(a) #a #define s(a) d(a) void main( void ) { puts(d(f(a,b))); puts(s(f(a,b))); } 输出结果: f(a,b) ab 分析: ##把两个符号连起来 #a指把a当成符号,就是把#后面的看成字符串 # 和 ## 操作符是和#define宏使用的. 使用# 使在#后的首个参数返回为一个带引号的字符串. 例如,

【LINQ技术】扩展特性和LINQ操作符

LINQ特有的编程结构 LINQ就像是嵌入到C#中的强类型查询语言,尽管和SQL查询很像,但语法却并不相同,甚至还有截然相反的一面. LINQ是在.NET发展到3.5版的时候被引进的,C#和VB语言都为此做了许多工作,扩展了大量新的编程结构. 一.隐式类型本地变量 var--一个如此小巧的关键字却有着强大的力量. var varInt=1; var varBool=True; var varString="String, String, String"; Console.WriteLi

LINQ to Entity Framework 操作符(转)

在开始了解LINQ to Entities之前,需要先对.NET Framework 3.5版本后对C#语言的几个扩展特性做一些阐释,这有助于我们更容易.更深刻的理解LINQ to Entities技术的原理与实现. 一.隐式实例化局部变量 .NET Framework 3.5后,实例化局部变量语法有了新的选择:使用“var”关键字隐式类型化: var user = new User(); 隐式类型化语法与Javascript语言里声明变量的语法类似,它可以一定程度上简化实例化局部变量的语法.但