JavaScript 构造函数 prototype属性和_proto_和原型链 constructor属性 apply(),call()和bind() 关键字this new操做符

1.构造函数:

一般构造函数首字母须要大写,主要是为了区别ECMAScript的其它函数。(高程三 P145)javascript

构造函数与其余函数的惟一区别,就在于调用它们的方式不一样。只要经过new来调用,任何函数都是构造函数;而任何函数,若是不经过new来调用,那么它和普通函数也没有任何区别。(P146)html

所谓"构造函数",其实就是一个普通函数,可是内部使用了this变量。对构造函数使用new运算符,就能生成实例,而且this变量会绑定在实例对象上。java

(就是一个普通的函数,与其余函数没有任何区别,能够理解为 函数==构造函数,它只是概念上的一个定义,使用它用来实例化对象。)web

 对于JavaScript的内置对象,Object、Array、Date等等这些都是构造函数。express

 this 上下文只存在两种语义,一种是被看成方法调用,this 指向调用它的对象;一种是做为函数调用,指向 Global 对象(严格模式下为 undefined)。 

2.  prototype(prototype属性)和 _proto_

 阮一峰 继承机制的设计思想   __proto__ VS. prototype in JavaScript   深刻理解JavaScript系列(10):JavaScript核心(晋级高手必读篇)编程

_proto_segmentfault

The use of __proto__ is controversial, and has been discouraged(有争议,不被鼓励的). It was never originally included in the EcmaScript language spec, but modern browsers decided to implement it anyway. Only recently, the __proto__ property has been standardized in the ECMAScript 2015 language specification for web browsers to ensure compatibility, so will be supported into the future. 数据结构

_proto_全部对象(包括函数)都有的,它才叫作对象的原型,原型链就是靠它造成的。(若是不是实在没有别的办法,是很是不建议在代码中使用的。)app

全部构造器/函数(函数也是对象)的__proto__都指向Function.prototype,它是一个空函数(Empty function)编程语言

Number.__proto__ === Function.prototype // true
Boolean.__proto__ === Function.prototype // true
String.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true
Function.__proto__ === Function.prototype // true
Array.__proto__ === Function.prototype // true
RegExp.__proto__ === Function.prototype // true
Error.__proto__ === Function.prototype // true
Date.__proto__ === Function.prototype // true

JavaScript中有内置(build-in)构造器/对象共计12个(ES5中新加了JSON),这里列举了可访问的8个构造器。剩下如Global不能直接访问,Arguments仅在函数调用时由JS引擎建立,Math,JSON是以对象形式存在的,无需new。它们的__proto__是Object.prototype。以下

Math.__proto__ === Object.prototype // true
JSON.__proto__ === Object.prototype // true

上面说的“全部构造器/函数”固然包括自定义的。以下

// 函数声明
function Person() {}
// 函数表达式
var Man = function() {}
console.log(Person.__proto__ === Function.prototype) // true
console.log(Man.__proto__ === Function.prototype) // true

函数也是对象,构造函数也是对象,能够理解为:构造函数是由“Function构造函数“实例化出来的函数对象

这说明什么呢?

全部的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身。全部构造器都继承了Function.prototype的属性及方法。如length、call、apply、bind(ES5)。

知道了全部构造器(含内置及自定义)的__proto__都是Function.prototype,那Function.prototype的__proto__是谁呢?

相信都据说过JavaScript中函数也是一等公民,那从哪能体现呢?以下

console.log(Function.prototype.__proto__ === Object.prototype)

这说明全部的构造器也都是一个普通JS对象,能够给构造器添加/删除属性等。同时它也继承了Object.prototype上的全部方法:toString、valueOf、hasOwnProperty等。

最后Object.prototype的__proto__是谁?

Object.prototype.__proto__ === null  // true

已经到顶了,为null。

实例是没有prototype属性的,prototype只有函数(准确地说是构造函数)才有的。它跟原型链没有半毛钱关系。

它的做用是:构造函数new对象的时候,告诉构造函数新建立的对象的原型是谁。是的,只在new一个对象的时候才起做用。当你new完获得这个对象后,随便你怎么改构造函数的prototype属性,都不会影响已建立的对象的原型链。

    function Father(){ // Code goes here
 } var obj1 = new Father();    // 此时,
    Father.prototype = { name:"hhhhh", last:"wwwww", sayName:function(){ alert(this.name); } }
obj1.sayName() // error
// 由于,构造函数的prototype属性被重写了,js的对象都是不相等的

 

调用构造函数时会为实例添加一个指向最初原型的[[prototype]]指针,而把原型修改成另一个对象就等于切断了构造函数与最初原型之间的联系。实例中的指针仅指向原型,而不指向构造函数。

 不过通常来讲,咱们会使用__<内部属性名>__ 下划线来代替双括号,例如__proto__(这是某些脚本引擎好比SpiderMonkey的对于原型概念的具体实现,尽管并不是标准).

若是一个对象的prototype没有显示的声明过或定义过,那么__proto__的默认值就是object.prototype, 而object.prototype也会有一个__proto__, 这个就是原型链的终点了,被设置为null。

2.1 prototype

Object.prototype  The Object.prototype property (是对象的属性)represents the Object prototype object. (prototype对象)

Javascript规定,每个构造函数都有一个prototype属性,指向另外一个对象。这个对象的全部属性和方法,都会被构造函数的实例继承。

这意味着,咱们能够把那些不变的属性和方法,直接定义在prototype对象上。

这个属性包含一个对象(如下简称"prototype对象"),全部实例对象须要共享的属性和方法,都放在这个对象里面;那些不须要共享的属性和方法,就放在构造函数里面。

实例对象一旦建立,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法,分红两种,一种是本地的,另外一种是引用(prototype对象)的。

2.2 _proto_    

参考资料  JavaScript中__proto__与prototype的关系     理解js中的原型链,prototype与__proto__的关系   参考资料三

 原型链如图所示:

 

3. constructor:(constructor属性)

MDN Object.prototype.constructor

Returns a reference to the Object constructor function that created the instance object(返回生成该实例的构造函数). Note that the value of this property is a reference to the function itself, not a string containing the function's name. 

constructor是部署在Object.prototype上的属性,因此位于原型链的最高一层(再高一层是null),任何对象(包括函数,都有constructor属性)

任何一个prototype对象都有一个constructor属性,指向它的构造函数。

                              eg:     Cat.prototype.constructor = Cat;

每个实例也有一个constructor属性(原型包含constructor属性,所以能够经过对象实例访问),默认调用prototype对象的constructor属性,即也指向它的构造函数. 

           eg:              var new cat = Cat(){};

                           cat.constructor = Cat;

 

 

原型对象的修改和重写是不同的。

修改:添加删除属性仍是在原来的prototype对象上作的修改。

重写:直接就用新的字面量对象来替换了,而字面量对象的constructor就是Object构造函数

4.  apply(),call(),bind()

每一个函数都包含两个非继承而来的方法:call()  和  apply()

这两个函数等于设置函数体内this对象的值

call和apply是Function的方法,第一个参数是this,第二个是Function的参数。好比函数里写了this,普通调用这个方法这个this多是window。而若是使用了call()或是apply(),第一个参数写啥,里面的this就是啥。(即改变了this的指向)

call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。由于 JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是能够改变的」这样的概念。

普通的函数调用 是隐式的传入 this,call 和 apply 能够显式指定它。

call() 和apply() 真正强大的地方是可以扩充函数赖以运行的做用域,并且好处在于对象不须要与方法有任何的耦合关系。

bind() 

5.   this关键字  

 参考资料,学会JS的this这一篇就够了,根本不用记  JavaScript中this指针指向的完全理解  javascript的this用法   掌握js中的this(一)    掌握js中的this(二)  

在函数代码中使用this时颇有趣,这种状况很难且会致使不少问题。

这种类型的代码中,this值的首要特色(或许是最主要的)是它不是静态的绑定到一个函数。

正如咱们上面曾提到的那样,this是进入上下文时肯定,在一个函数代码中,这个值在每一次彻底不一样。

无论怎样,在代码运行时的this值是不变的,也就是说,由于它不是一个变量,就不可能为其分配一个新值(相反,在Python编程语言中,它明确的定义为对象自己,在运行期间能够不断改变)。

总的原则,那就是this指的是,调用函数的那个对象。
通俗点讲, this 只是一个引用别名(referencing alias) - 这个别名只知道当前指向的那个对象, 而这也是最棘手的地方。
简而言之, this 是一个特殊的标识符关键字 —— 在每一个 function 中自动根据做用域(scope) 肯定, 指向的是这次调用的 “全部者,owner” (即 那个对象)

this 是如何建立的?每调用一次 JavaScript 函数时,都会建立一个新的对象, 其中的信息包括: 传入了哪些参数, 函数是如何调用(invoked)的, 函数是在哪里被调用(called)的,等等。该对象中还有一个重要的属性是 this 引用, 函数是哪一个对象的方法,this 就会自动绑定到该对象。

分析一下call的用法

  • Step1: 把第二个到最后一个参数做为函数执行时要传入的参数
  • Step2: 函数执行时的this指向第一个参数
  • Step3: 在上面这个特殊的上下文中执行函数
function say(word) { console.log(world); } say("Hello world");                            // 二者是
say.call(window, "Hello world");               // 等效的

每次看见functionName(xxx)的时候,你须要立刻在脑海中把它替换为functionName.call(window,xxxx),

this 的做用域(scope) 与函数定义的位置没有关系, 而是取决于函数在哪里被调用( where they are called from ;i.e. the context)。

状况一:纯粹的函数调用
这是函数的最一般用法,属于全局性调用,所以this就表明全局对象Global。

  function test(){

    this.x = 1;

    alert(this.x);

  }

  test(); // 1

状况二:做为对象方法的调用
 函数还能够做为某个对象的方法调用,这时this就指这个上级对象。
 
 状况三 做为构造函数调用
所谓构造函数,就是经过这个函数生成一个新对象(object)。这时,this就指这个新对象。
 
状况四 apply调用
apply()是函数对象的一个方法,它的做用是改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。所以,this指的就是这第一个参数。

其实秘密花园里面总结的不错(与上面的四点是一一对应)
1.当在所有范围内使用 this,它将会指向全局对象。

2.函数调用时,这里 this 也会指向全局对象。

3.方法调用 test.foo(); 这个例子中,this 指向 test 对象。

4.调用构造函数 new foo(); 若是函数倾向于和 new 关键词一块使用,则咱们称这个函数是构造函数。在函数内部,this 指向新建立的对象。

关于 this 的知识点

和其余机制同样, this 关键字也遵循一些简单的规则, 若是你了解了这些规则,那就能够用得顺畅一些。下面快速回顾这两节中所学的知识点:

  • 在下列状况下 this 指向的是全局对象: 
    当函数做为父对象的属性被调用时, this 指向的是父对象(parent object)。
    • 在最外层的代码中, 不在任何 function 里面
    • 不是对象方法(method)的函数(method)里面
    • 不是构造函数(constructor)的函数里面
  • 当函数经过 call() 、 apply() 或者 bind()调用时, this指向的是传递给这些方法的第一个参数。若是第一个参数是 null或者不是一个对象, 那么 this 指向的是全局对象。
  • 在使用 new 操做符来调用一个函数时, this 指向的是新建立的这个对象。
  • 在 ECMAScript 6 中使用箭头函数时, this 根据所处的语法做用域指向上级对象(parent object)。

了解了这些简单直接的规则,咱们就能够很容易地看出 this 指向的是哪一个对象, 若是指向不正确, 那能够用学过的这些黑科技来搞定。

new operator(new 操做符)

mdn  

The new operator creates an instance of a user-defined object type(?对象类型,仍是理解为不一样的数据结构?) or of one of the built-in object types that has a constructor function. 

new 操做符生成一个实例,这个实例是用户自定义的“对象类型”或是内建的对象类型的实例。

Description:

Creating a user-defined object requires two steps:

  1. Define the object type by writing a function.经过一个函数(构造函数)来定义一种对象类型
  2. Create an instance of the object with new.用new操做符生成一个这种对象类型的实例

To define an object type, create a function for the object type that specifies its name and properties. An object can have a property that is itself another object. 

new操做符的原理

When the code new Foo(...) is executed, the following things happen:

  1. A new object is created, inheriting(一个新的对象生成,继承自构造函数的prototype属性对象) from Foo.prototype.
  2. The constructor function Foo is called with the specified arguments, and with this bound to the newly created object(构造函数被调用,而且把this关键字绑定到新生成的对象上)new Foo is equivalent to new Foo(), i.e. if no argument list is specified, Foo is called without arguments.
  3. The object returned by the constructor function becomes the result of the whole newexpression. If the constructor function doesn't explicitly return an object(若构造函数没有显示的返回对象,则第一步生成的对象就会被返回), the object created in step 1 is used instead. (Normally constructors don't return a value, but they can choose to do so if they want to override the normal object creation process.) 

(高程三,建立对象,new操做符的做用) 

test

相关文章
相关标签/搜索