// new 的实现原理 // 简单的双向绑定 1.new 2.Function 3.this 如果函数挂载在一个对象上,作为对象的一个属性,就称它为对象的方法。当通过这个对象来调用函数时,该对象就是此次调用的上下文(context),也就是该函数的this的值。 4.constructor 用于初始化一个新创建的对象的函数就是此次调用的上下文。 在JS中函数即对象,程序可以随意操控它们。比如:JS可以把函数赋值给变量,或者作为参数传递给其他函数。因为函数就是对象,所以可以给它们设置属性,甚至调用它们的方法。 JS的函数可嵌套在其他函数中定义,这样它们就可以访问它们被定义时所处的作用域中的任何变量。这意味着JS函数构成了一个闭包(closure),它给JS带来了非常强劲的编程能力。
嵌套函数
function hypotenuse(a, b) {
function square(x) {
return x * x
}
return Math.sqrt(square(a) + square(b))
}
function square(x) {return x * x}
function hypotenuse(a, b) {
return Math.sqrt(square(a) + square(b))
}
函数调用 构成函数主体的JS代码在执行之时并不会调用,只有调用该函数时,它们再回执行。有4种方式来调用JS函数。
1.作为函数调用,对于普通的函数调用,函数的返回值成为调用表达式的值。如果该函数返回值是因为解释器到达结尾,返回值就是undefined。如果函数返回是因为解释器执行到一条return语句,返回值就是return之后的表达式的值,如果return语句没有值,则返回undefined。
2.作为方法调用,方法和this关键字是面向对象编程范例的核心。任何函数只要作为方法调用实际上都会传入一个隐式的实参------这个实参是一个对象,方法调用的母体就是这个对象。
var o = {
m: function () {
var self = this
console.log(this === o)
f()
function f() {
console.log(this === o)
console.log(self === o)
}
}
}
o.m()
3.作为构造函数
如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。构造函数调用和普通的函数调用以及方法调用在实参处理、调用上下文和返回值方面都有不同。 构造函数调用创建一个新的空对象,这个对象继承自构造函数的prototype属性。构造函数试图初始化这个新创建的对象,并将这个对象用做其调用上下文,因此构造函数可以使用this关键字来引用这个新创建的对象。
4.通过它们的call()和apply()方法间接调用
JS中函数也是对象,函数也可以包含方法。 函数可以被任意次执行或调用。
原型链 1.创建对象有几种方法 2.原型、构造函数、实例、原型链 3.instanceof的原理 4.new运算符
1.创建对象有几种方法
方法1
var a = {name: 'mary'}
var b = new Object({name: 'john'})
a、b结果相同
方法2
var M = function(name) {this.name = name}
var c = new M('henri')
方法3
var P = {name: 'john'}
var d = Object.create(P)
d.__proto__ === p // true
每一个JS对象都和另一个对象相关联,每一个对象都从原型继承属性。
2.原型、构造函数、实例、原型链
实例:a,b,c都称为实例 构造函数:构造函数也是函数,任何函数只要被new操作的函数,就是构造函数。不使用new就是普通的函数。 函数:函数都有一个prototype属性,声明函数的时候就会被js引擎带上。对象没有prototype。实例有__proto__,函数没有。 原型对象:通过constructor(构造器)来区分被哪个构造函数所引用。
M.prototype.constructor === M
c.__proto__ === M.prototype
M.__proto__ === Function.prototype
M.prototype.__proto__ === Object.prototype // true
Object.prototype是整个原型链的顶端
M.prototype.run = function () {
console.log('run fast')
}
var e = new M('mary')
此时c、e都有了run方法
- instanceof 原理
instanceof判断对象的类型
判断实例对象的__proto__和构造函数的prototype是否为同一个引用(同一个地址),整条原型链上的都会返回true
c instanceof M // true
c instanceof Object // true
c.__proto__ === M.prototype // true
M.prototype.__proto === Object.prototype // true
c.__proto__.constructor === M // true
c.__proto__.constructor === Object // false
因此用constructor比用instanceof更严谨
- new运算符
4.1 一个新对象被创建。它继承自foo.prototype 4.2 构造函数foo被执行。执行的时候,相应的传参会被传入,同时上下文(this)会被指定为这个新实例。new foo等同于new foo(),只能用在不传递任何参数的情况下 4.3 如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象
new运算符背后的原理
var f = function(func) {
var o = Object.create(func.prototype)
var k = func.call(o)
if (typeof k === 'object') {
return k
} else {
return o
}
}
var h = f(M)
h instanceof M
h instanceof Object
h.__proto__.constructor === M
函数实际上是对象,每个函数都是Function类型的实例,而且与其他引用类型一样具有属性和方法。由于函数就是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。M.proto === Function.prototype function M () {
} M.proto === Function.prototype
用constructor判断比instanceof要准确
__proto__
- 对象特有
- 指向上层(创建自己的那个构造函数)的
prototype - 因此对象可以从
prototype中继承属性和方法
prototype
- 函数特有
- 用于存储要共享的属性和方法
constructor
- 函数特有,定义在
prototype里面 - 通过new创建实例时,该实例变继承了
prototype的属性和方法
Object:既是对象,也是构造函数
- 作为对象:
Object.__proto__===Function.prototype - 作为函数:
Object.prototype是原型链的顶端,Object.prototype.__proto = null
Function: 既是对象,也是构造函数
- 作为对象:
Function.__proto__===Function.prototype - 作为函数:
Function.prototype用于共享,而Function.prototype.__proto__继承自Object.prototype
Array(Date、Number...):既是对象,也是构造函数
- 作为对象:
Array.__proto__===Function.prototype - 作为函数:
Array.prototype用于共享,Array.prototype.__proto__继承自Object.prototype
对象Person: 既是对象,也是构造函数
- 作为对象:
Person.__proto__===Function.prototype - 作为函数:
Person.prototype用于共享,·Person.prototype.__proto继承自Object.prototype
因此:
1、原型链顶端是Object.prototype
2、构造函数创建的对象(Object、Fucntion、Array、普通对象等)都是Function的实例,它们的__proto__均指向Function.prototype
3、除了Object,所有对象(或构造函数)的prototype,均继承自Object.prototype