从一个实例,看new FunctionName()的内部机制
下面的代码:
function Dog(name) {
this.name = name;
Dog.prototype = { shout: function() { alert("I am " + this.name); } };
}
var dog1 = new Dog("Dog 1");
dog1.shout();
上面的代码看起来很“优美”,可一运行,却报错:Object #<Dog> has no method 'shout'
在 YUI 3 学习笔记:oop 中,曾提到过,对于代码:
Fn() {}; var fn = new Fn();
new Fn() 的实际构造过程可以等价为以下伪代码:
var o = {__proto__: Fn.prototype}; Fn.apply(o); return o;
理解了 new 的构造过程,我们可以分析上面的实例了。
首先,JS引擎在遇到函数声明 function Dog(…) 时,会给函数对象添加 prototype 属性,伪代码如下:
Dog.prototype = {constructor: Dog};
当运行到 var dog1 = new Dog(”Dog 1″) 时,内部操作:
var o = {__proto__: Dog.prototype}; Dog.apply(o); return o
也许你已经知道问题所在了。为了更清楚,添加点注释:
// Dog.prototype = {constructor: Dog}; var o = {__proto__: Dog.prototype}; // 此时,o = {__proto__: {constructor: Dog}} Dog.apply(o); // 此时,Dog.prototype = {shout: function(){...}} return o;
显然,运行 dog1.shout() 时,dog1 的确没有 shout 方法。
(个人验证:
console.log(dog1.__proto__ === Dog.prototype);
输出为false。
上面的解释不是很清楚,可以这么理解,在我们在创建dog1的时候,一般是Dog1的prototype已经确定了的,但这里prototype在构造的时候更改了,
导致我们的_proto__发生改变了。
为什么改为下面的就可以了:
function Dog(name) {
this.name = name;
}
Dog.prototype = { shout: function() { alert("I am " + this.name); } };
var dog1 = new Dog("Dog 1");
dog1.shout();//输出 i am dog1
因为是Dog.prototype首先确定下面了,再dog1=new Dog("dog1");
上面的代码:
console.log(dog1.__proto__.constructor);
输出的是:function Object() { [native code] } 说明指向 的是Object。看http://www.cnblogs.com/youxin/p/3219175.html 这个图就明白了。
)
考考大家:
function Dog(name) {
this.name = name;
Dog.prototype = { shout: function() { alert("I am " + this.name); } };
}
var dog1 = new Dog("Dog 1");
var dog2 = new Dog("Dog 2");
dog2.shout();
dog1.shout();
请问运行结果是什么?
(i'm dog2 ,第二个dog1没有方法shout,运行错误)
注意是先创建的dog1,而后调用dog1.)
最后,想大声疾呼:作为一门语言,JavaScript 有自己的脾性。用 Java 等代码方式去书写 JavaScript 代码,是不妥当的。在不使用框架的情况下,一次性添加多个方法时,推荐以下书写风格:
function Dog(name) { this.name = name; }
Dog.prototype = { constructor: Dog, shout: function() { \* ... *\ }, run: function() { \* ... *\ } };
http://lifesinger.org/blog/2009/08/new-funtion-secret/#more-2103
从一个实例,看new FunctionName()的内部机制的更多相关文章
- 从一个实例看javascript几种常用格式的转换
要对如图一所示的左侧table的数据按照“总量”进行排序 1,在前端实现 2,数据格式为object,如图二 原创文章,转载请注明:http://www.cnblogs.com/phpgcs java ...
- 从一个死锁看mysql innodb的锁机制
背景及现象 线上生产环境在某些时候经常性的出现数据库操作死锁,导致业务人员无法进行操作.经过DBA的分析,是某一张表的insert操 作和delete操作发生了死锁.简单介绍下数据库的情况(因为涉及到 ...
- 关于类、方法、对象(实例):通过一个例子看一下self都做了哪些事情
我们在定义一个类时,经常会在类的各个方法中看到self,那么在程序执行时self到底起了什么作用,什么时候要加self,这一点需要我们思考并好好理解.之前在学习时没有想这么多,加之用pycharm写代 ...
- Singleton单例模式是最简单的设计模式,它的主要作用是保证在程序执行生命周期中,使用了单类模式的类仅仅能有一个实例对象存在。
...
- C# 只启动一个实例完全解决方案
工作上经常会遇到"程序只能启动一个实例"这样的需求. 我想,这样的需求应该很普遍,所以没打算去动脑筋,去找谷歌问下就得了,用下来发现,不是这里不爽就是那里不行. 先说下我详细的几点 ...
- C语言入门(17)——C语言数组应用的一个实例
本篇通过一个实例介绍使用数组的一些基本模式.问题是这样的:首先生成一列0-9的随机数保存在数组中,然后统计其中每个数字出现的次数并打印,检查这些数字的随机性如何.随机数在某些场合(例如游戏程序)中是非 ...
- 苹果公司的新的编程语言 Swift 高级语言(十一)--初始化类的析构函数的一个实例
一 .实例的初始化 实例的初始化是准备一个类.结构或枚举的实例以便使用的过程. 初始化包含设置一个实例的每个存储属性为一个初始值,以及运行不论什么其他新的实例可以使用之前须要的设置或 ...
- spring得到实例和new一个实例,哪个快?
spring配置的bean是默认单例,那么在程序中,得到一个实例一定比创建一个实例的速度快,也更加省资源.今天实际测试的时候发现,new 一个对象比spring得到一个对象快多了.后面自己又加了个单例 ...
- vc++高级班之窗口篇[4]---让程序只运行一个实例
大家都看过或者使用过类似只运行一个实例的程序,比如:QQ游戏.部分浏览器 等等! 让一个程序只运行一个实例的方法有多种,但是原理都类似,也就是在程序创建后,有窗口的程序在窗口创建前, 检查系统中是 ...
随机推荐
- git安装及使用简介
从源代码安装 有人觉得从源码安装 Git 更实用,因为你能得到最新的版本. 二进制安装程序倾向于有一些滞后,当然近几年 Git 已经成熟,这个差异不再显著. 如果你想从源码安装 Git,需要安装 Gi ...
- join函数——Gevent源码分析
在使用gevent框架的时候,我们经常会使用join函数,如下: def test1(id): print(id) gevent.sleep(0) print(id, 'is done!') t = ...
- Android小代码——设置全屏
1: public class MainActivity extends Activity { 2: @Override 3: public void onCreate(Bundle savedIns ...
- Spring中的DataBinding(二) - Validation
@Controller@RequestMapping(value = "/custom/register")public class RegistrationController ...
- MYSQL truncate table
准备: 要说truncate table 就要先说一下delete 它们两个都可以用来从表中删除数据行!表面上看是delete 删除的慢一些,truncate table 快一些. delete : ...
- Myeclipse 2014配置SVN详细图解
1.什么是SVN? 管理软件开发过程中的版本控制工具. 2.myeclipse安装SVN插件步骤,以myeclipse 2014为例. (1)下载SVN插件 http://subclipse.tigr ...
- SharedPreference对象及其xml文件
SharedPreferences对象----->getXXX SharedPreferences.Editor对象---->putXXX
- java设计模式--行为型模式--命令模式
命令模式 概述 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤消的操作. 适用性 .抽象出待执行的动作以参数化某对象. .在不同的时刻指定.排 ...
- hdu 1599 find the mincost route_最小环
#include <iostream> #include<cstdio> using namespace std; #define N 110 #define INF 0xff ...
- mysql root@::1 意义
root@::1 ::1 是IPv6格式的 127.0.0.1