Object.create 和 new 区别与原理

Object.create 和new 区别与原理

今天无意中看到一篇关于 Object.create 和 new 区别的博客,看完后觉得很不对劲。再一看评论,果然有问题。所以写个通俗易懂的博客,也再次理清自己的思绪。我会先说原型链的一些概念,从原型链讲他们的区别,引出继承的例子,顺便引出 new 实现的原理,最后给出完整的 Object.create 规范

(一)Object.create 和 new 区别

因为那篇文章的作者似乎没弄清原型链的一些问题,所以首先你得有这个概念,参考我以前博客

ES6 Class 的原生写法
https://blog.csdn.net/u014168594/article/details/79448711

在这里插入图片描述

截取我博客中的图:

1.Object.create 是创建一个新对象,使用现有的对象来提供新创建对象的 _proto_。意思就是生成一个新对象,该新对象的 _proto_(原型) 指向现有对象。

2.new 生成的是构造函数的一个实例,实例继承了构造函数及其 prototype(原型属性)上的属性和方法。

function a(){
	this.name = 1
}
a.prototype.sayName = function(){
	console.log(1)
}
var a1 = new a()
var a2 = Object.create(a.prototype)

看上面代码,从代码分析更直观

对象 a2 的 _proto_ 指向 a.prototype, 只继承了 a 的原型方法 sayName

在这里插入图片描述

a1 是构造函数 a 的实例,继承了构造函数 a 的属性 name及其 prototype(原型) 的原型方法 sayName

在这里插入图片描述

两者不同在于,Object.create 创建的新函数并没有继承构造函数的属性和方法,只继承了原型方法和原型属性

这就是为什么组合寄生式继承优于普通的组合继承的地方,因为之前已经继承过一次,不再重复继承多一次原型的属性和方法。

组合继承

function SuperType(name) {	
	this.name = name;	
	this.colors = ["red","green","black"];
}; 
SuperType.prototype.sayName = function() {
	return this.name
}; 
function SubType(name, age) {	
	SuperType.call(this, name);	//继承一次
	this.age = age;
}; 

/* 普通组合继承 */
SubType.prototype = new SuperType();	//继承第二次

/* 组合寄生 */
function inherit(sub,super){
	var prototype = Object.create(super.prototype)	//不发生第二次继承
	prototype.constructor =  sub
	sub.prototype = prototype 
}
inherit(SubType,SuperType)

SubType.prototype.sayAge = function () {return this.age};

(二)new 实现原理

从上面几张图我们已经知道了 new 其实就是在实现 Object.create (使用现有的对象来提供新创建的对象 _proto_)的基础上,继承了原对象的属性和方法

function a(){
	this.name = 1
}
a.prototype.sayName = function(){
	console.log(1)
}
var a1 = new a()

这个例子实际上就干了三件事

var a1 = {}		//创建一个空对象
a1._proto_  =  a.prototype	//使用现有的对象来提供新创建对象的  \_proto_
a.call(a1) 		//继承原对象属性和方法

所以我们在对象原型里面 x.prototype 里面增加属性和方法会被继承,就是因为这个 proto 属性

(三)Object.create() 规范

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。

Object.create(proto, [propertiesObject])

proto

新创建对象的原型对象,可以为 null。

propertiesObject

可选。如果没有指定为 undefined,则是要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数

返回值

一个新对象,带着指定的原型对象和属性。

例子

var o = {}
o = Object.create(Object.prototype, {
	// foo会成为所创建对象的数据属性
	foo: { 
		writable:true,
		configurable:true,
		value: "hello" 
	},
	// bar会成为所创建对象的访问器属性
	bar: {
		configurable: false,
		get: function() { return 10 },
		set: function(value) {
		  console.log("Setting `o.bar` to", value);
		}
	}
});
  • 7
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
目 录 1 这是一个什么样的故事...........................................................................................................6 2 这是关于谁的故事...................................................................................................................8 2.1 sequence........................................................................................................................8 2.2 sequence_item...............................................................................................................8 2.3 sequencer.....................................................................................................................10 3 故事背后的故事.....................................................................................................................13 3.1 整体架构.....................................................................................................................14 3.2 sequence_item生成.....................................................................................................14 3.2.1 my_sequence_item..........................................................................................14 3.2.2 òvm_object_utils_begin.................................................................................16 3.2.3 òvm_field_utils_begin...................................................................................18 3.2.4 òvm_object_utils_end....................................................................................19 3.3 sequencer的生成.........................................................................................................20 3.3.1 my_sequnecer..................................................................................................20 3.3.2 òvm_sequencer_utils.....................................................................................20 3.3.3 òvm_sequencer_utils_begin...........................................................................21 3.3.4 òvm_componen
JAVA高级特性 1.静态导入:先举个离例子 。 import java.lang.Integer.parseInt; public class StaticImport { int x = parseInt("123"); System.out.println(x); } 这样的程序如果不在IDE 工具中输入,是很难看出这个程序代码会出现问题,可它偏偏就出问题了,这是为什么呢?因为程序里面有个静态方法,如果导入import static java.lang.Integer.parseInt;这样的程序就可以运行了。 2.可变参数与for循环增强 这个是一般的用法: public static void loop(String[] args){ for(int i=0;i<args.length;i++) { System.out.println(args[i]); } } 这个是JDK 增加的新特性的用法! public static void loop(int x,int... args ) { //这里的参数一定要以这样的形式输入 for(int i:args) { System.out.println(i); } } 3.枚举 写枚举技巧: 1. enum Gender{MALE,FEMALE,BOTH} 2. enum Gender{MALE,FEMALE,BOTH;public abstract getTitle();} 3.enum Gender{MALE{},FEMALE{},BOTH{};public abstract getTitle();} 4.填充各个{}中的getTitle方法。 下面是个红绿黄灯的例子: public enum TrafficLamp { RED(30){ public TrafficLamp next() { return GREEN; } }, GREEN(50){ public TrafficLamp next() { return YELLOW; } }, YELLOW(5){ public TrafficLamp next() { return RED; } }; public abstract TrafficLamp next(); private int time; private TrafficLamp(int time) { this.time = time; } 4.反射. 这个知识点,真是费了我好大劲才理解。当真正理解了,其实也就不难了。先举例子来理解什么是反射。 先建这样的一个类,带会下面有个类里面有反射成员变量的方法的! public class ReflectPoint { private int x; public int y; public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; } } public class Test{ String obj = (String)Class.forName("java.lang.String").newInstance(); 这是制造另一个章:Class.forName("java.lang.Integer") --------------------- 讲Constructor://构造方法 Constructor constructors[] = Class.forName("java.lang.String").getConstructors(); Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class); String str = (String)constructor.newInstance(new StringBuffer("abc")); System.out.println(str); class.newInstance()内部其实就是在用默认的构造方法 ----------------------- 讲Method //方法 Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class); System.out.println(charAt.invoke(str, 1)); ------------------------- 讲Field //成员变量 ReflectPoint point = new ReflectPoint(1,7); Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("y"); y.setAccessible(true); System.out.println(y.get(point)); Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x"); x.setAccessible(true); System.out.println(x.get(point)); } 在这里我们运行的时候可以看出,ReflectPoint类里面的x和y 都可以打印出来了! 学习心得:先从这四个知识点来看,张老师的确很让人敬佩!以上的一些程序代码均为张老师课堂即兴发挥所写,也可以看出,张老师对JAVA特性的深刻理解能力!现在说说我对这些程序代码的理解,说实话,才开始听张老师讲的时候,我感觉很模糊的,但是当我真正理解了之后,觉得这些程序写的真是太好了。象以后我门在学习JAVA 的时候,一定要对每个知识点要慢慢的消化吃透,切不能走马观花。一个知识点必须要反复的动手练习,不然很难理解其中的奥秘所在的! 5.在JAVA的程序中,我经常性的看到字符前面有@这种标志的符号.这个就叫做注解! 下面是使用 @SuppressWarnings 来取消 deprecation 警告的一个例子: public class Test { @Deprecated //在eclipse下运行的时候,方法名上会加一横线 public static void sayHello() { } } public class Test2 { @SuppressWarnings("deprecation") //在mian方法内调用一个没有定义的方法时,运行的时候将会出现这一注解! public static void main(String [] args) { Test.sayHello(); } } @SuppressWarnings 批注允许您选择性地取消特定代码段(即,类或方法)中的警告。其中的想法是当您看到警告时,您将调查它,如果您确定它不是问题,您就可以添加一个 @SuppressWarnings 批注,以使您不会再看到警告。虽然它听起来似乎会屏蔽潜在的错误,但实际上它将提高代码安全性,因为它将防止您对警告无动于衷 — 您看到的每一个警告都将值得注意。 由如下代码引出@Override的讲解: User类中的方法: public boolean equals(User other) { return name.equals(other.name); } 下面的代码执行时将有问题: User user1 = new User(); User user2 = new User(); user1.setName("abc"); user2.setName("abc"); System.out.println(user1.equals(user2)); HashSet set = new HashSet(); set.add(user1); set.add(user2); System.out.println(set.size());//期望结果为1,但实际为2 这时候在User类的equals方法上加上@Override,发现了问题。 再看看这个代码:一看就知道有问题, 这里 就有个很好的解决办法,在写public @interface MyAnnotation {}这样的类的时候,下面的代码上的错误提示就是结束的! public class dsds { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub System.out.println(User.class.isAnnotationPresent(MyAnnotation.class) ); System.out.println( User.class.getAnnotation(MyAnnotation.class) ); } } 运行的结果为:false null 下面演示了一下@Target和@Retention import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE}) //用于构造方法 @Retention(RetentionPolicy.RUNTIME) //在运行是加载Annotation到JVM中 public @interface MyAnnotation { public String value() default "yellow"; public int[] array() default {1,2}; public MetaAnnotation annotation() ; } 注解最主要的就是这么多,其实注解真正的,我们都很少留心的,但是有的注解会给你在写程序和查找错误的时,会有很大的帮助的! 6.泛型: 1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。 2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。 3、泛型的类型参数可以有多个。 4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上成为“有界类型”。 5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(java.lang.String); 例子: a..使用?通配符可以引用其他各种参数化的类型,但不能调用与参数化有关的方法; Collection<?> c = new Vector<String>(); c.add("abc");//报错 c.size();//正确 所以,?通配符定义的变量主要用作引用,调用与参数化无关的方法,如果要调用与参数化相关的方法,那么必须在使用?通配符引用之前调用,否则就与java 5提供泛型的目的背道而驰了。 b..向下限定通配符: 正确:Vector<? extends Number> x = new Vector<Integer>(); 错误:Vector<? extends Number> x = new Vector<String>(); 向上限定通配符: 正确:Vector<? super Integer> x = new Vector<Number>(); 错误:Vector<? super Integer> x = new Vector<Byte>(); 7.代理 这里就直接先应用张老师写的代码然后再讲清其原理吧! package cn.itcast.corejava; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Collection; import java.util.Vector; public class ProxyTest { public static void main(String[] args) { System.out.println(Integer.class.getClassLoader()); //System.out.println(ProxyTest.class.getClassLoader().getParent().getClass().getName()); System.out.println(ProxyTest.class.getClassLoader().getClass().getName()); //test1(); //test2(); } private static void test3() { Vector v = new Vector(); class MyInvocationHandler implements InvocationHandler { Collection target = null; public Collection bind(Collection target) { this.target = target; Collection proxy1 = (Collection)Proxy.newProxyInstance( ProxyTest.class.getClassLoader(), new Class[]{Collection.class} , this); return proxy1; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("begin " + method.getName()); Object retval = method.invoke(target, args); System.out.println("end" + method.getName()); return retval; } } MyInvocationHandler handler = new MyInvocationHandler(); Collection proxy1 = handler.bind(v); System.out.println(proxy1.getClass().getName()); proxy1.add("abc"); proxy1.add("xyz"); System.out.println(proxy1.size()); } private static void test2() { Vector v = new Vector(); class MyInvocationHandler implements InvocationHandler { Collection target = null; public MyInvocationHandler(){} public MyInvocationHandler(Collection target){this.target = target;} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("begin " + method.getName()); Object retval = method.invoke(target, args); System.out.println("end" + method.getName()); return retval; } } Collection proxy1 = (Collection)Proxy.newProxyInstance( ProxyTest.class.getClassLoader(), new Class[]{Collection.class} , new MyInvocationHandler(v)); System.out.println(proxy1.getClass().getName()); proxy1.add("abc"); proxy1.add("xyz"); System.out.println(proxy1.size()); } private static void test1() { Collection proxy = (Collection)Proxy.newProxyInstance( ProxyTest.class.getClassLoader(),//first parameter new Class[]{Collection.class} , //second parameter new InvocationHandler(){ //third parameter Vector target = new Vector(); public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("begin " + method.getName()); Object retval = method.invoke(target, args); System.out.println("end" + method.getName()); return retval; } } ); System.out.println(proxy.getClass().getName()); proxy.add("abc"); proxy.add("xyz"); System.out.println(proxy.size()); } } 以下是Proxy的API文档: public class Proxyextends extends Object implements Serializable Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. To create a proxy for some interface Foo: InvocationHandler handler = new MyInvocationHandler(...); Class proxyClass = Proxy.getProxyClass( Foo.class.getClassLoader(), new Class[] { Foo.class }); Foo f = (Foo) proxyClass. getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler }); or more simply: Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler);从以上的程序中在方法中定义参数的时候总是三个参数,可这三个参数有分别代表什么意思呢!?现在以我自己个人的理解,比如我是买家,我要买本书,可是现在我有事,是不是需要别人代我买呢?那带我买的人是不是一定要到卖书的地方买呢?所以着中间产生了三个实体.说白了就是一种代理机制.需要三方一起运行! 代理其实很好理解的,而且会用固定的语法格式,很快会掌握这一原理的!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值