标签:大写 def zh-cn var 实例化 hello === 第一个 something
函数可以有属性,对象也可以有属性,在函数名前使用 new
操作符即可返回一个函数的实例化对象
function fn () {}
fn.a = ‘haha‘
console.log(fn.a) //"haha"
let obj = {}
obj.a = ‘heihei‘
console.log(obj.a) //"heihei"
let newObj = new fn()
每个函数都有一个属性(prototype)原型对象,发现有constructor
属性和 __poroto__
属性,constructor
指向创建它的构造器函数,这里要明确的是 函数也会有构造函数,而这个__poroto__
与它的构造函数的 prototype 是同一个东西,见图 虚线指向的CFp就是构造函数的prototype,小的cf 是通过CF创建的对象实例
// fn.prototype
{
constructor: ? doSomething(),
__proto__: {
constructor: ? Object(),
hasOwnProperty: ? hasOwnProperty(),
isPrototypeOf: ? isPrototypeOf(),
propertyIsEnumerable: ? propertyIsEnumerable(),
toLocaleString: ? toLocaleString(),
toString: ? toString(),
valueOf: ? valueOf()
}
}
我们既可以在CF上添加属性,也可以在prototype
添加
区分:函数上添加属性,构造函数生成实例上添加、函数原型添加
function fn() {
this.c = ‘c‘
}
fn.a = ‘a‘
fn.prototype.b = ‘b‘
let obj = new fn()
obj.d = ‘d‘
// fn.prototype 上定义 属性b ,obj定义了属性d,fn上添加了属性 a,
// fn函数内部有个this的属性c, 那么obj有几个属性呢? 答案是 c b d
下面就来分析下为什么会这样,首先图中的CF上的P1、P2在对象实例中均存在,参考下面的代码
function CF(){
this.p1 = ‘p1‘,
this.p2 = ‘p2‘
}
let cf1 = new CF()
见下图
可以看到属性均出现在了对象实例上,现在就来说一下构建实例的发生了什么
不过this上的属性构造函数是不具有的,而在函数上直接定义的属性它当然是有的,通过prototyoe
设置的是在图的CFp位置的,实例继承它,也就是对象实例会得到这些属性,对象实例在添加prototype
属性前创建依然有效
函数和对象的关系也就清楚了,通过构造函数方式可以创建对象,且可以得到函数原型上的属性和方法,也可以在构造函数里通过this为其设置一些不是公有的属性方法等
扩展:
使用this添加的属性具有一定“私有”性,但是还有些需要注意的地方,见下面代码
function fn() {
let value = ‘a‘
this.a = ‘a‘
this.privateValues = function (){
return value
}
}
let newObj1 = new fn()
let newObj2 = new fn()
console.log(newObj1.a === newObj2.a) //true,基本类型的比较只比较值
console.log(newObj1.privateValues === newObj2.privateValues)
// false,每次进入对象都不相同
使用函数将其包裹起来返回具有更好的“私有”性
使用对象重写原型对象
function fn() {}
fn.prototype = {
name: ‘kangkang‘,
sayName: {
console.log(this.name)
}
}
使用对象重写会导致创建一个新的prototype
对象, 对象里的 constructor
不再指向构造函数,这时需要重新指定下
function fn() {}
fn.prototype = {
constructor: fn
name: ‘kangkang‘,
sayName: {
console.log(this.name)
}
}
这里的继承想要有个较为深刻的理解,首先需要介绍下原型链:
每个实例对象(object )都有一个私有属性(称之为 proto)指向它的原型对象(prototype)。该原型对象也有一个自己的原型对象 ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节
参考MDN
由于每个实例都会继承原型链上的原型对象上的属性或方法,当你使用某个实例上所没有的属性时,会依着原型链一层一层寻找,那么继承这个概念也就很清楚了,我们将原型对象给需要继承的对象不就行了吗?其实之间会有些问题
function father() {}
function son() {}
father.prototype.sayHello = function() {
console.log(‘hello‘)
}
son.prototype = father.prototype
let obj = new son()
obj.sayHello() // hello
//
father.prototype.sayHello = function() {
console.log(‘haha‘)
}
obj.sayHello() // haha
son.prototype.sayHello = function() {console.log(‘ddd‘)}
father.prototype.sayHello() //ddd
上面这种“继承”是有问题的,不仅互相影响而且当father修改原型时会直接影响到son,进行改进
function father() {}
function son() {}
father.prototype.sayHello = function() {
console.log(‘hello‘)
}
function wa() { }
wa.prototype = father.prototype
son.prototype = new wa()
son.prototype.constructor = son
son.prototype.sayHello = function() {console.log(‘sss‘)}
father.prototype.sayHello() //hello
ECMAScript 5 中引入了一个新方法:Object.create(). 可以调用这个方法来创建一个新对象。新对象的原型就是调用 create 方法时传入的第一个参数
var a = {a: 1};
// a ---> Object.prototype ---> null
var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (继承而来)
var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null
var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty);
// undefined, 因为d没有继承Object.prototype
上面还是有点缺点,当 原型对象上有引用类型值得属性时
function a () {
this.obj = {
name: ‘kangkang‘,
age: 3
}
}
function b() {
this.b = ‘b‘
}
b.prototype = new a()
var c = new b()
var d = new b()
c.obj.name=‘xixi‘
console.log(d.obj.name) //xixi
这时创建的实例在每次获得构造函数的引用值属性时,获得的值相同,值保存的是引用类型的地址,自然是同一个引用值了,所以互相影响,解决方法
看下面代码
function fn (name) {
this.score = [90,98,99]
this.name = name
}
function a () {
fn.call(this,‘kangkang‘)
this.age = 3
}
var c = new a()
var d = new a()
c.score[0] = 100
console.log(c.score) //[100, 98, 99]
console.log(d.score) //[90, 98, 99]
这种方法又缺少了原型上的继承,所以结合起来就是
function fn (name) {
this.score = [90,98,99]
this.name = name
}
fn.prototype.sayName = function() { console.log(this.name) }
function a () {
fn.call(this,‘kangkang‘)
this.age = 3
}
a.prototype = new fn()
a.prototype.constructor = a
var c = new a()
var d = new a()
c.score[0] = 100
console.log(c.score) //[100, 98, 99]
console.log(d.score) //[90, 98, 99]
console.log(c.sayName()) // kangkang
ES6 实现了 class
,其中有 class
constructor
static
extends
super
这些关键字完整的实现“类”的功能, 它是语法糖,是基于上面所说的原型的概念实现的
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
class Square extends Polygon {
constructor(sideLength) {
super(sideLength, sideLength);
}
get area() {
return this.height * this.width;
}
set sideLength(newLength) {
this.height = newLength;
this.width = newLength;
}
}
var square = new Square(2);
static
用法
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
}
const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
console.log(Point.distance(p1, p2)); //7.0710678118654755
// 注意此处不是从实例中调用它的
拓展:
ES6属性简写和方法简写 参考阮一峰老师的博客
const o = {
method() {
return "Hello!";
}
};
// 等同于
const o = {
method: function() {
return "Hello!";
}
};
function f(x, y) {
return {x, y};
}
// 等同于
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}
以上为查阅资料总结而得,如要详细准确还请自行查阅方能辨析有所得
标签:大写 def zh-cn var 实例化 hello === 第一个 something
原文地址:https://www.cnblogs.com/daixixi/p/9406604.html