理解javascript

---出自 《node.js开发指南》

提起面向对象的程序设计语言,立刻让人想起的是C++、Java 等这类静态强类型语言,以及Python、Ruby 等脚本语言,它们共有的特点是基于类的面向对象。而说到JavaScript,
很少能让人想到它面向对象的特性,甚至有人说它不是面向对象的语言,因为它没有类。没错,JavaScript 真的没有类,但JavaScript 是面向对象的语言。JavaScript 只有对象,对象就是对象,不是类的实例。
因为绝大多数面向对象语言中的对象都是基于类的,所以经常有人混淆类的实例与对象的概念。对象就是类的实例,这在大多数语言中都没错,但在JavaScript 中却不适用。
JavaScript 中的对象是基于原型的,因此很多人在初学JavaScript 对象时感到无比困惑。通过这一节,我们将重新认识JavaScript 中对象,充分理解基于原型的面向对象的实质。

构造函数

function User(name, uri)
{
    this.name = name;
    this.uri = uri;
    this.display = function ()
    {
        console.log(this.name);
    }
}
var someuser = new User(‘byvoid‘, ‘http://www.byvoid.com‘); 

上下文对象

在JavaScript 中,上下文对象就是 this 指针,即被调用函数所处的环境。上下文对象的作用是在一个函数内部引用调用它的对象本身,JavaScript 的任何函数都是被某个对象调用的,包括全局对象,所以 this 指针是一个非常重要的东西。

this 指针永远是这个引用所属的对象

var someuser = {
    name: ‘byvoid‘,
    func: function ()
    {
        console.log(this.name);
    }
};
var foo = {
    name: ‘foobar‘
};
someuser.func(); // 输出byvoid
foo.func = someuser.func;
foo.func(); // 输出foobar
name = ‘global‘;
func = someuser.func;
func(); // 输出global

call 和 apply

call 和 apply 的功能是以不同的对象作为上下文来调用某个函数。简而言之,就是允许一个对象去调用另一个对象的成员函数

call 和 apply 的功能是一致的,两者细微的差别在于 call 以参数表来接受被调用函数的参数,而 apply 以数组来接受被调用函数的参数。call 和 apply 的语法分别是:
func.call(thisArg[, arg1[, arg2[, ...]]])
func.apply(thisArg[, argsArray])
其中,func 是函数的引用,thisArg 是 func 被调用时的上下文对象,arg1、arg2 或argsArray 是传入 func 的参数

var someuser = {
    name: ‘byvoid‘,
    display: function (words)
    {
        console.log(this.name + ‘ says ‘ + words);
    }
};
var foo = {
    name: ‘foobar‘
};
someuser.display.call(foo, ‘hello‘); // 输出foobar says hello 

someuser.display 是被调用的函数,它通过 call 将上下文改变为 foo 对象,因此在函数体内访问 this.name 时,实际上访问的是foo.name,因而输出了foobar。

bind

可以用 call 或 apply 方法,但如果重复使用会不方便,因为每次都要把上下文对象作为参数传递,而且还会使代码变得不直观。针对这种情况,我们可以使用 bind 方法来永久地绑定函数的上下文,使其无论被谁调用,上下文都是固定的。bind 语法如下:
func.bind(thisArg[, arg1[, arg2[, ...]]])

bind 方法还有一个重要的功能:绑定参数表,如下例所示。

var person = {
    name: ‘byvoid‘,
    says: function (act, obj)
    {
        console.log(this.name + ‘ ‘ + act + ‘ ‘ + obj);
    }
};
person.says(‘loves‘, ‘diovyb‘); // 输出byvoid loves diovyb
byvoidLoves = person.says.bind(person, ‘loves‘);
byvoidLoves(‘you‘); // 输出byvoid loves you

可以看到,byvoidLoves 将 this 指针绑定到了person,并将第一个参数绑定到loves,之后在调用 byvoidLoves 的时候,只需传入第三个参数。这个特性可以用于创建一个函数的“捷径”,之后我们可以通过这个“捷径”调用,以便在代码多处调用时省略重复输入相同的参数。

原型与构造函数

? 构造函数内定义的属性继承方式与原型不同,子对象需要显式调用父对象才能继承构造函数内定义的属性。
? 构造函数内定义的任何属性,包括函数在内都会被重复创建,同一个构造函数产生的两个对象不共享实例。
? 构造函数内定义的函数有运行时闭包的开销,因为构造函数内的局部变量对其中定义的函数来说也是可见的

//下面这段代码可以验证以上问题:
function Foo() {
    varinnerVar = ‘hello‘;
    this.prop1 = ‘BYVoid‘;
    this.func1 = function ()
    {
        innerVar = ‘‘;
    };
}
Foo.prototype.prop2 = ‘Carbo‘;
Foo.prototype.func2 = function ()
{
    console.log(this.prop2);
};
var foo1 = new Foo();
var foo2 = new Foo();
console.log(foo1.func1 == foo2.func1); // 输出false
console.log(foo1.func2 == foo2.func2); // 输出true 

? 除非必须用构造函数闭包,否则尽量用原型定义成员函数,因为这样可以减少开销。
? 尽量在构造函数内定义一般成员,尤其是对象或数组,因为用原型定义的成员是多个实例共享的。

原型链

JavaScript 中有两个特殊的对象:Object 与Function,它们都是构造函数,用于生成对象。

Object.prototype 是所有对象的祖先,Function.prototype 是所有函数的原型,包括构造函数。

我把JavaScript 中的对象分为三类,一类是用户创建的对象,一类是构造函数对象,一类是原型对象。

用户创建的对象,即一般意义上用new 语句显式构造的对象。

构造函数对象指的是普通的构造函数,即通过 new 调用生成普通对象的函数。

原型对象特指构造函数prototype 属性指向的对象。

这三类对象中每一类都有一个__proto__ 属性,它指向该对象的原型,从任何对象沿着它开始遍历都可以追溯到 Object.prototype。
构造函数对象有prototype 属性,指向一个原型对象,通过该构造函数创建对象时,被创建对象的 __proto__ 属性将会指向构造函数的 prototype 属性。原型对象有constructor属性,指向它对应的构造函数。

让我们通过下面这个例子来理解原型:

function Foo() {
}
Object.prototype.name = ‘My Object‘;
Foo.prototype.name = ‘Bar‘;
var obj = new Object();
var foo = new Foo();
console.log(obj.name); // 输出My Object
console.log(foo.name); // 输出Bar
console.log(foo.__proto__.name); // 输出Bar
console.log(foo.__proto__.__proto__.name); // 输出My Object
console.log(foo.__proto__.constructor.prototype.name); // 输出Bar 

在JavaScript 中,继承是依靠一套叫做原型链(prototype chain)的机制实现的。属性继承的本质就是一个对象可以访问到它的原型链上任何一个原型对象的属性。例如上例的foo 对象,它拥有foo. __proto__ 和 foo. __proto__.__proto__ 所有属性的浅拷贝(只复制基本数据类型,不复制对象)。所以可以直接访问foo.constructor(来自foo.__proto__,即Foo.prototype),foo.toString(来自foo. __proto__.__proto__,即Object.prototype)。

理解javascript,布布扣,bubuko.com

时间: 2024-10-19 05:54:37

理解javascript的相关文章

深入理解javascript闭包

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function

深入理解JavaScript中创建对象模式的演变(原型)

创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Object构造函数和对象字面量方法 工厂模式 自定义构造函数模式 原型模式 组合使用自定义构造函数模式和原型模式 动态原型模式.寄生构造函数模式.稳妥构造函数模式 第一部分:Object构造函数和对象字面量方法 我之前在博文<javascript中对象字面量的理解>中讲到过这两种方法,如何大家不熟悉,可以点进去看一看回顾一下.它们的优点是用来创建单个的对象非常方

深入理解JavaScript中的属性和特性

深入理解JavaScript中的属性和特性? JavaScript中属性和特性是完全不同的两个概念,这里我将根据自己所学,来深入理解JavaScript中的属性和特性. 主要内容如下: 理解JavaScript中理解对象的本质.理解对象与类的关系.对象与引用类型的关系 对象属性如何进行分类 属性中特性的理解 第一部分:理解JavaScript中理解对象的本质.理解对象与类的关系.对象与引用类型的关系 对象的本质:ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值.对象或者函数.即

0003.深入理解JavaScript系列学习:编写高质量JavaScript代码的基本要点

推荐 汤姆大叔博客园深入理解JavaScript系列 此文来源:http://www.cnblogs.com/TomXu/archive/2011/12/28/2286877.html 书写可维护的代码(Writing Maintainable Code ) 即 代码的可读写维护性 博客园<行者自若的技术笔记> 中参考代码规范与读写可维护性 可作为参考,我也转载了文章到自己的博客园 http://www.cnblogs.com/wolongjv/articles/5937898.html 概括

【干货理解】理解javascript中实现MVC的原理

理解javascript中的MVC MVC模式是软件工程中一种软件架构模式,一般把软件模式分为三部分,模型(Model)+视图(View)+控制器(Controller); 模型:模型用于封装与应用程序的业务逻辑相关的数据以及对数据处理的方法.模型有对数据直接访问的权利.模型不依赖 "视图" 和 "控制器", 也就是说 模型它不关心页面如何显示及如何被操作. 视图:视图层最主要的是监听模型层上的数据改变,并且实时的更新html页面.当然也包括一些事件的注册或者aja

彻底理解JavaScript原型

原型是JavaScript中一个比较难理解的概念,原型相关的属性也比较多,对象有"[[prototype]]"属性,函数对象有"prototype"属性,原型对象有"constructor"属性. 为了弄清原型,以及原型相关的这些属性关系,就有了这篇文章. 相信通过这篇文章一定能够清楚的认识到原型,现在就开始原型之旅吧. 认识原型 开始原型的介绍之前,首先来认识一下什么是原型? 在JavaScript中,原型也是一个对象,通过原型可以实现对象的属

深入理解javascript原型和闭包(15)——闭包

http://www.cnblogs.com/wangfupeng1988/p/3994065.html 深入理解javascript原型和闭包(15)——闭包

深入理解JavaScript系列(结局篇)(转载)

深入理解JavaScript系列(结局篇) 介绍 最近几个月忙得实在是不可开交,终于把<深入理解JavaScript系列>的最后两篇“补全”了,所谓的全是不准确的,因为很多内容都没有写呢,比如高性能.Ajax安全.DOM详解.JavaScript架构等等.但因为经历所限,加上大叔希望接下来写点其它东西,所以此篇文字就暂且当前完结篇的总结吧,以后有时间的话,可以继续加上一些未涉及的专题内容. 网络文章来源 本系列文章参考了大量的互联网网站,在此向各位网站拥有者.博主.提到的以及未提到的作者们说一

深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点(转)

才华横溢的Stoyan Stefanov,在他写的由O’Reilly初版的新书<JavaScript Patterns>(JavaScript模式)中,我想要是为我们的读者贡献其摘要,那会是件很美妙的事情.具体一点就是编写高质量JavaScript的一些要素,例如避免全局变量,使用单变量声明,在循环中预缓存length(长度),遵循代码阅读,以及更多. 此摘要也包括一些与代码不太相关的习惯,但对整体代码的创建息息相关,包括撰写API文档.执行同行评审以及运行JSLint.这些习惯和最佳做法可以

JavaScript大杂烩6 - 理解JavaScript中的this

在JavaScript开发中,this是很常用的一个关键字,但同时也是一个很容易引入bug的一个关键字,在这里我们就专门总结一下页面中可能出现的this关键字(包括几种在其他页面文件中出现的this). JavaScript中的this关键字通常只使用在函数中,它指向当前函数的调用者,这是this关键字的本质,所有的使用方式都是围绕这个展开的,让我们来看一下在各种性质的函数中this的用法.1. 在对象的函数中使用this var person = { name: 'Frank', say: f